How to Fix 'state not updating' in AutoGen (TypeScript)
What “state not updating” usually means
In AutoGen TypeScript, this error usually means your agent ran, but the state object you expected to persist was never actually mutated in the place AutoGen reads from. It shows up most often when you wire custom memory, message handlers, or agent state into a conversation and then assume a local variable update is enough.
The common symptom is: the chat completes, but the next turn still sees old values. In logs, you’ll often see patterns like state not updating, stale AgentState, or behavior that looks like the agent ignored your last tool result.
The Most Common Cause
The #1 cause is mutating a copied object instead of returning or assigning the updated state that AutoGen expects.
This happens a lot when people use Map, spread objects, or callback closures and think they changed shared state. In AutoGen, if your handler returns a new state shape or expects an immutable update flow, changing a nested local reference can be a no-op.
Broken vs fixed pattern
| Broken pattern | Fixed pattern |
|---|---|
| Mutates a local copy and never writes it back | Returns the updated state explicitly |
Assumes state is shared by reference | Treats state as immutable and reassigns |
| Works in one turn, fails on the next | Persists across turns |
// BROKEN
import { AssistantAgent } from "@autogen/agent";
type MyState = {
counter: number;
lastMessage?: string;
};
const agent = new AssistantAgent({
name: "support-agent",
modelClient,
// Looks fine, but this mutates a copied value in many flows
onMessage: async (ctx) => {
const state = ctx.state as MyState;
const next = { ...state };
next.counter += 1;
next.lastMessage = ctx.message.content;
console.log("updated:", next);
// No return / no assignment back to AutoGen-owned state
},
});
// FIXED
import { AssistantAgent } from "@autogen/agent";
type MyState = {
counter: number;
lastMessage?: string;
};
const agent = new AssistantAgent({
name: "support-agent",
modelClient,
onMessage: async (ctx) => {
const state = ctx.state as MyState;
const nextState: MyState = {
...state,
counter: state.counter + 1,
lastMessage: ctx.message.content,
};
return {
...ctx,
state: nextState,
};
},
});
If you’re using RoutedAgent, AssistantAgent, or a custom runtime hook, the rule is the same: don’t mutate an object you don’t own. Return the new state through the API path AutoGen uses for persistence.
Other Possible Causes
1) You forgot to register persistent storage
If your agent restarts between turns and there’s no storage backend, your “state” only lives in memory.
// BROKEN: ephemeral only
const runtime = new SingleThreadedAgentRuntime();
// no persistence configured
// FIXED: wire durable storage
const runtime = new SingleThreadedAgentRuntime({
persistence: sqlitePersistence,
});
If you’re using an in-memory runtime in dev, expect resets after process restart.
2) Your reducer/tool handler returns the wrong shape
AutoGen won’t apply updates if your handler returns data that doesn’t match what the framework expects.
// BROKEN
return {
counter: state.counter + 1,
};
// FIXED
return {
...ctx,
state: {
...state,
counter: state.counter + 1,
},
};
This shows up when you mix message payloads with agent state and forget that they are separate objects.
3) You are reading stale closure values
A classic TypeScript bug: your callback captures an old state value from setup time.
let currentState = { counter: 0 };
agent.onMessage(async () => {
console.log(currentState.counter); // stale if never reassigned properly
});
Fix it by reading from ctx.state inside the handler every time.
agent.onMessage(async (ctx) => {
console.log((ctx.state as { counter: number }).counter);
});
4) Multiple agents are updating different copies of “the same” state
If you pass cloned objects into each agent, each one updates its own copy and nothing converges.
const shared = { ticketsClosed: 0 };
const a1 = makeAgent({ state: { ...shared } });
const a2 = makeAgent({ state: { ...shared } }); // separate copy
Use one source of truth:
const sharedStateRef = sharedStore.get("conversation-123");
const a1 = makeAgent({ state: sharedStateRef });
const a2 = makeAgent({ state: sharedStateRef });
Or better, centralize writes through one runtime/state store.
How to Debug It
- •
Log before and after every mutation
- •Print
ctx.state, your computednextState, and what you return. - •If
nextStatechanges but later turns don’t reflect it, persistence is broken. - •If
nextStatenever changes, your logic is wrong before AutoGen sees it.
- •Print
- •
Check whether you are returning the updated object
- •Search for handlers that end with side effects only.
- •In AutoGen flows, returning nothing often means no persisted update.
- •Look for functions like
onMessage, tool callbacks, reducers, or event handlers.
- •
Verify runtime/storage configuration
- •Confirm whether you’re using ephemeral memory or durable persistence.
- •If you use
SingleThreadedAgentRuntimewithout storage, restart behavior will look like “state not updating.” - •Check whether your environment creates a fresh runtime per request.
- •
Inspect object identity
- •Add logs for references if needed:
console.log(Object.is(ctx.state, nextState)); - •If everything is cloned repeatedly, one agent may not see another agent’s updates.
- •If you rely on mutation semantics but the framework expects immutability, fix that first.
- •Add logs for references if needed:
Prevention
- •Treat AutoGen state as immutable unless the specific API says otherwise.
- •Keep one persistent store per conversation or session ID.
- •Write tests that run two consecutive turns and assert the second turn sees the first turn’s update.
- •Don’t mix message payloads, local variables, and persisted agent state in the same object unless you control all write paths.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit