How to Fix 'state not updating when scaling' in CrewAI (TypeScript)
If you’re seeing state not updating when scaling in a CrewAI TypeScript project, the core issue is usually simple: your agent or task state is being mutated in one place, but the scaled workers are reading a different instance. This shows up when you move from a single-run flow to parallel execution, or when you scale tasks across multiple agents and expect shared state to “just work”.
In practice, this usually means one of three things: you’re mutating a local object instead of the canonical store, you’re cloning state before dispatch, or your task context is not being passed through the Crew/Task boundary correctly.
The Most Common Cause
The #1 cause is mutating an object after it has already been handed off to CrewAI. In TypeScript, this often happens when you pass a plain object into Task or Crew, then update that object later and expect workers to see the change.
CrewAI won’t magically track your local variable references across scaled execution. If the worker got a snapshot, it stays a snapshot.
Broken vs fixed pattern
| Broken pattern | Fixed pattern |
|---|---|
| Mutate local state after task creation | Build immutable state and pass it explicitly |
| Assume shared references survive scaling | Recreate task input from current source of truth |
| Rely on side effects inside callbacks | Return updated state and persist it centrally |
// BROKEN
import { Agent, Task, Crew } from "crewai";
type AppState = {
customerId: string;
riskScore: number;
};
const state: AppState = {
customerId: "cust_123",
riskScore: 42,
};
const analyst = new Agent({
name: "RiskAnalyst",
role: "Underwriter",
goal: "Assess customer risk",
});
const task = new Task({
description: `Review customer ${state.customerId} with risk score ${state.riskScore}`,
agent: analyst,
});
// State changes AFTER task creation
state.riskScore = 87;
const crew = new Crew({
agents: [analyst],
tasks: [task],
});
await crew.kickoff();
// FIXED
import { Agent, Task, Crew } from "crewai";
type AppState = {
customerId: string;
riskScore: number;
};
function buildTask(state: AppState) {
return new Task({
description: `Review customer ${state.customerId} with risk score ${state.riskScore}`,
agent: new Agent({
name: "RiskAnalyst",
role: "Underwriter",
goal: "Assess customer risk",
}),
});
}
let state: AppState = {
customerId: "cust_123",
riskScore: 42,
};
state = { ...state, riskScore: 87 };
const crew = new Crew({
agents: [],
tasks: [buildTask(state)],
});
await crew.kickoff();
The important part is this:
- •don’t mutate objects that were already captured by a task
- •rebuild the task from current data
- •treat input state as immutable once dispatched
Other Possible Causes
1. You are scaling with cloned context objects
If you do something like structuredClone(), spread syntax, or JSON serialization before dispatching work, each worker gets its own copy. That means updates in one branch won’t appear in another.
const baseState = { policyId: "pol_001", step: "review" };
const workerState = structuredClone(baseState);
workerState.step = "approval";
// baseState.step is still "review"
If you need shared updates, store them in a central persistence layer like Redis, Postgres, or your app database.
2. You are using non-deterministic mutable globals
This bites people when they keep workflow data in module-level variables.
let currentCaseId = "";
export function setCase(id: string) {
currentCaseId = id;
}
In scaled execution, one worker may overwrite another worker’s value. Use request-scoped context instead.
export function buildContext(caseId: string) {
return { caseId };
}
3. Your task output schema does not match what downstream code expects
Sometimes the error looks like state isn’t updating, but the real problem is that your parser drops fields because the model output doesn’t match your expected shape.
type Result = {
status: string;
nextStep?: string;
};
If the agent returns:
{ "status": "approved", "next_step": "notify_customer" }
then nextStep stays undefined. Normalize field names with an explicit parser or schema validator.
4. You are hitting an async race condition in parallel tasks
When multiple tasks update the same record without locking, later writes can overwrite earlier ones.
await Promise.all([
saveCase({ id: "c1", status: "reviewing" }),
saveCase({ id: "c1", status: "approved" }),
]);
The final value depends on timing. Use optimistic locking, version checks, or queue writes through a single updater.
How to Debug It
- •
Log the exact state before task creation
- •Print the object right before
new Task(...). - •If the value is already wrong there, the bug is upstream.
- •Print the object right before
- •
Log inside each worker boundary
- •Add debug output at agent/task entry points.
- •Compare what was passed in versus what each scaled worker sees.
- •
Check for cloning or serialization
- •Search for
JSON.parse(JSON.stringify(...)),structuredClone, message queue payloads, or API boundaries. - •If present, assume you have copies, not shared references.
- •Search for
- •
Verify output mapping
- •Inspect raw agent output before parsing.
- •If your code expects
nextStepbut receivesnext_step, fix the schema mismatch first.
A good rule here:
- •if logs differ before and after dispatch, it’s a propagation problem
- •if logs match but persisted data is wrong, it’s a write/race problem
- •if logs show missing fields only after parsing, it’s a schema problem
Prevention
- •Treat all CrewAI inputs as immutable once a
Taskis created. - •Pass context explicitly into every agent/task instead of relying on module globals.
- •Persist shared workflow state in an external store if more than one worker can touch it.
If you want stable scaling behavior in CrewAI TypeScript projects, design for copy-on-dispatch and explicit state transitions. That keeps your workflow predictable when you move from single-agent execution to parallel crews.
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