[GH-ISSUE #547] new StateBackend() crashes on write_file / edit_file, while (runtime) => new StateBackend(runtime) works #273

Open
opened 2026-06-05 17:21:24 -04:00 by yindo · 2 comments
Owner

Originally created by @luizzappa on GitHub (May 20, 2026).
Original GitHub issue: https://github.com/langchain-ai/deepagentsjs/issues/547

Summary

Passing an explicit StateBackend instance to createDeepAgent() appears to break filesystem tool calls in some runtimes.

In my case, asking the agent to create a file causes a crash, but:

  • omitting backend entirely works
  • using a backend factory works: const backend = (runtime) => new StateBackend(runtime);

The docs/examples suggest new StateBackend() is valid, and some integrations (for example, interpreter with skillsBackend) benefit from sharing a backend reference explicitly.

Versions

  • deepagents: 1.10.2
  • @langchain/quickjs: 0.4.0
  • langchain: 1.4.x

Reproduction

Minimal shape:

import { createDeepAgent, StateBackend } from "deepagents";
const backend = new StateBackend();
const agent = createDeepAgent({
  model: "openai:gpt-5.4",
  backend,
});
const stream = await agent.streamEvents(undefined, {
  configurable: {
    thread_id: "thread-1",
  },
  version: "v3",
  context: {},
});

Then prompt the agent with something that triggers write_file, for example:

Create a file /notes.txt with the content hello

Actual behavior

The tool call fails with:

TypeError: Cannot read properties of undefined (reading 'configurable')
    at MiddlewareError.wrap (errors.js:77:10)
    at ToolNode.wrappedHandler [as wrapToolCall] (utils.js:393:67)
    at async ToolNode.runTool (ToolNode.js:265:11)
    at async ToolNode.run (ToolNode.js:300:15)
    at async ToolNode.invoke (RunnableCallable.js:40:23)
    at async RunnableSequence.invoke (base.js:973:69)
    at async _runWithRetry (retry.js:55:13)
    at async PregelRunner._executeTasksWithRetry (runner.js:148:24)
    at async PregelRunner.tick (runner.js:69:49)
    at async CompiledStateGraph._runLoop (index.js:1223:5)
Caused by: TypeError: Cannot read properties of undefined (reading 'configurable')
    at get files (index.js:657:81)
    at StateBackend.write (index.js:753:24)
    at Object.write (index.js:487:41)

Expected behavior

I’d expect one of these to be true:

  1. new StateBackend() should work correctly when passed explicitly to createDeepAgent(), or
  2. the docs/examples should clearly say that StateBackend must be passed as a factory:
    const backend = (runtime) => new StateBackend(runtime);

Right now the instance form and factory form are not equivalent in practice.

Workaround

This works reliably for me:

import { createDeepAgent, StateBackend } from "deepagents";
import { createCodeInterpreterMiddleware } from "@langchain/quickjs";
const backend = (runtime) => new StateBackend(runtime);
const agent = createDeepAgent({
  model: "openai:gpt-5.4",
  backend,
  skills: ["/skills/"],
  middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })],
});

Omitting backend also works, but that does not help when another middleware needs the same backend reference.

Possible cause

It looks like there are two different StateBackend code paths:

  • zero-arg instance mode: new StateBackend()
  • runtime-injected mode: new StateBackend(runtime)

The runtime-injected form works, while the zero-arg form eventually tries to read from getConfig().configurable and crashes because that config is undefined in this execution path.

So this seems like either:

  • a runtime bug in StateBackend zero-arg mode, or
  • a docs/API inconsistency where the instance form is presented as supported but is not actually safe in all runtimes.
Originally created by @luizzappa on GitHub (May 20, 2026). Original GitHub issue: https://github.com/langchain-ai/deepagentsjs/issues/547 # Summary Passing an explicit `StateBackend` instance to `createDeepAgent()` appears to break filesystem tool calls in some runtimes. In my case, asking the agent to create a file causes a crash, but: - omitting backend entirely works - using a backend factory works: `const backend = (runtime) => new StateBackend(runtime);` The docs/examples suggest `new StateBackend()` is valid, and some integrations (for example, interpreter with `skillsBackend`) benefit from sharing a backend reference explicitly. # Versions - deepagents: 1.10.2 - @langchain/quickjs: 0.4.0 - langchain: 1.4.x # Reproduction Minimal shape: ```typescript import { createDeepAgent, StateBackend } from "deepagents"; const backend = new StateBackend(); const agent = createDeepAgent({ model: "openai:gpt-5.4", backend, }); const stream = await agent.streamEvents(undefined, { configurable: { thread_id: "thread-1", }, version: "v3", context: {}, }); ``` Then prompt the agent with something that triggers `write_file`, for example: `Create a file /notes.txt with the content hello` # Actual behavior The tool call fails with: ``` TypeError: Cannot read properties of undefined (reading 'configurable') at MiddlewareError.wrap (errors.js:77:10) at ToolNode.wrappedHandler [as wrapToolCall] (utils.js:393:67) at async ToolNode.runTool (ToolNode.js:265:11) at async ToolNode.run (ToolNode.js:300:15) at async ToolNode.invoke (RunnableCallable.js:40:23) at async RunnableSequence.invoke (base.js:973:69) at async _runWithRetry (retry.js:55:13) at async PregelRunner._executeTasksWithRetry (runner.js:148:24) at async PregelRunner.tick (runner.js:69:49) at async CompiledStateGraph._runLoop (index.js:1223:5) Caused by: TypeError: Cannot read properties of undefined (reading 'configurable') at get files (index.js:657:81) at StateBackend.write (index.js:753:24) at Object.write (index.js:487:41) ``` # Expected behavior I’d expect one of these to be true: 1. `new StateBackend()` should work correctly when passed explicitly to `createDeepAgent()`, or 2. the docs/examples should clearly say that `StateBackend` must be passed as a factory: `const backend = (runtime) => new StateBackend(runtime);` Right now the instance form and factory form are not equivalent in practice. # Workaround This works reliably for me: ```typescript import { createDeepAgent, StateBackend } from "deepagents"; import { createCodeInterpreterMiddleware } from "@langchain/quickjs"; const backend = (runtime) => new StateBackend(runtime); const agent = createDeepAgent({ model: "openai:gpt-5.4", backend, skills: ["/skills/"], middleware: [createCodeInterpreterMiddleware({ skillsBackend: backend })], }); ``` Omitting backend also works, but that does not help when another middleware needs the same backend reference. # Possible cause It looks like there are two different `StateBackend` code paths: - zero-arg instance mode: `new StateBackend()` - runtime-injected mode: `new StateBackend(runtime)` The runtime-injected form works, while the zero-arg form eventually tries to read from `getConfig().configurable` and crashes because that config is undefined in this execution path. So this seems like either: - a runtime bug in StateBackend zero-arg mode, or - a docs/API inconsistency where the instance form is presented as supported but is not actually safe in all runtimes.
Author
Owner

@hntrl commented on GitHub (Jun 2, 2026):

@luizzappa could you give some details on what environment you're running deepagents in? This zero-arg path might break because we depend on async context in certain environments to sauce backend (like you mentioned)

<!-- gh-comment-id:4607056941 --> @hntrl commented on GitHub (Jun 2, 2026): @luizzappa could you give some details on what environment you're running deepagents in? This zero-arg path might break because we depend on async context in certain environments to sauce backend (like you mentioned)
Author
Owner

@luizzappa commented on GitHub (Jun 2, 2026):

@hntrl , sure. My use case is running deepagents directly in the browser, client-side.

Because this is a browser environment, Node async context is not available/reliable. In our bundle, node:async_hooks is stubbed, so code paths that depend on AsyncLocalStorageProviderSingleton.getRunnableConfig() do not work. That is why the zero-arg new StateBackend() path breaks for us: it eventually relies on async context to recover the LangGraph config.

The runtime-backed form works for this environment:

const backend = (runtime) => new StateBackend(runtime);

const agent = createDeepAgent({
  backend,
  // ...
});

That said, TypeScript currently marks this constructor signature as deprecated:

The signature (runtime: BackendRuntime<unknown>, options?: BackendOptions): StateBackend of StateBackend is deprecated.ts(6387)

So from a browser/client-side perspective, it would be really helpful if either:

  • the runtime-backed StateBackend(runtime) constructor were not deprecated, since it is the reliable option when async context is unavailable, or
  • zero-arg new StateBackend() could be made to work without requiring async context.
<!-- gh-comment-id:4608372114 --> @luizzappa commented on GitHub (Jun 2, 2026): @hntrl , sure. My use case is running `deepagents` directly in the browser, client-side. Because this is a browser environment, Node async context is not available/reliable. In our bundle, `node:async_hooks` is stubbed, so code paths that depend on `AsyncLocalStorageProviderSingleton.getRunnableConfig()` do not work. That is why the zero-arg `new StateBackend()` path breaks for us: it eventually relies on async context to recover the LangGraph config. The runtime-backed form works for this environment: ```ts const backend = (runtime) => new StateBackend(runtime); const agent = createDeepAgent({ backend, // ... }); ``` That said, TypeScript currently marks this constructor signature as deprecated: ``` The signature (runtime: BackendRuntime<unknown>, options?: BackendOptions): StateBackend of StateBackend is deprecated.ts(6387) ``` So from a browser/client-side perspective, it would be really helpful if either: - the runtime-backed `StateBackend(runtime)` constructor were not deprecated, since it is the reliable option when async context is unavailable, or - zero-arg `new StateBackend()` could be made to work without requiring async context.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/deepagentsjs#273