How to Fix 'JSON parsing error when scaling' in CrewAI (TypeScript)
When CrewAI throws JSON parsing error when scaling, it usually means the framework tried to serialize or deserialize agent/task state and hit something that is not valid JSON. In TypeScript projects, this often shows up after you add more agents, pass richer objects through task context, or scale from a single local run to multiple workers.
The error is rarely about “JSON” in the abstract. It’s usually one bad value in your agent config, task payload, tool output, or memory state that breaks serialization during a scaling step.
The Most Common Cause
The #1 cause is passing non-serializable values into CrewAI objects or task context. In TypeScript, this usually means functions, class instances, Date, Map, Set, BigInt, circular references, or raw SDK clients getting stuffed into agent inputs.
CrewAI expects plain JSON-compatible data for anything it needs to persist or move across boundaries.
Broken vs fixed
| Broken pattern | Fixed pattern |
|---|---|
| Passing a live client instance into task input | Passing only plain JSON data |
| Returning complex objects from tools | Returning stringified/plain objects |
| Storing runtime-only values in agent state | Keeping runtime-only values outside CrewAI state |
// BROKEN
import { Agent, Task } from "crewai";
const crmClient = new CRMClient(process.env.CRM_API_KEY!);
const task = new Task({
description: "Summarize customer profile",
expectedOutput: "A short summary",
// This will often blow up during serialization/scaling
input: {
customerId: "cus_123",
client: crmClient,
createdAt: new Date(),
},
});
const agent = new Agent({
role: "Analyst",
goal: "Summarize customer data",
backstory: "Works with CRM records",
});
// FIXED
import { Agent, Task } from "crewai";
const task = new Task({
description: "Summarize customer profile",
expectedOutput: "A short summary",
input: {
customerId: "cus_123",
createdAt: new Date().toISOString(),
},
});
// Keep the client outside CrewAI state
const crmClient = new CRMClient(process.env.CRM_API_KEY!);
const agent = new Agent({
role: "Analyst",
goal: "Summarize customer data",
backstory: "Works with CRM records",
});
If you need the client in a tool, instantiate it inside the tool function and return plain data:
import { Tool } from "crewai";
export const fetchCustomerTool = new Tool({
name: "fetch_customer",
description: "Fetch customer profile by ID",
func: async (input: string) => {
const { customerId } = JSON.parse(input);
const client = new CRMClient(process.env.CRM_API_KEY!);
const customer = await client.getCustomer(customerId);
return JSON.stringify({
id: customer.id,
name: customer.name,
status: customer.status,
});
},
});
Other Possible Causes
1. Tool returns non-JSON output
If a tool returns an object with methods, circular refs, or undefined fields in nested structures, CrewAI can fail while trying to scale work across agents.
// BAD
func: async () => {
return someSdkResponse; // often not plain JSON
}
// GOOD
func: async () => {
const response = await someSdk.fetchData();
return JSON.stringify({
id: response.id,
name: response.name,
score: response.score,
});
}
2. Environment config contains invalid values
If you load config from env vars and pass raw values into tasks, watch for accidental undefined, empty strings where objects are expected, or malformed JSON strings.
// BAD
const settings = JSON.parse(process.env.CREW_SETTINGS!); // crashes if invalid
new Task({ input: settings });
// GOOD
const rawSettings = process.env.CREW_SETTINGS ?? "{}";
let settings;
try {
settings = JSON.parse(rawSettings);
} catch {
settings = {};
}
new Task({ input: settings });
3. Circular references in shared state
This happens when you attach request objects, ORM entities, or parent-child graphs to task context.
// BAD
const user = await db.user.findUnique({ where: { id } });
(user as any).request = req; // circular / non-serializable
new Task({ input: user });
// GOOD
const user = await db.user.findUnique({ where: { id } });
new Task({
input: {
id: user.id,
email: user.email,
plan: user.plan,
},
});
4. Mixed string/object payloads between agents
One agent may emit a stringified JSON blob while another expects an object. During scaling, that mismatch can surface as a parsing failure.
// BAD
const resultFromAgentA = '{"status":"ok"}';
new Task({
input: resultFromAgentA, // downstream expects object
});
// GOOD
const resultFromAgentA = JSON.parse('{"status":"ok"}');
new Task({
input: resultFromAgentA,
});
How to Debug It
- •
Find the exact boundary where serialization happens
- •Check whether the error appears when creating a
Task, passing context between agents, or returning tool output. - •The stack trace often points to something like
JSON.parse,JSON.stringify, or internal CrewAI scaling code.
- •Check whether the error appears when creating a
- •
Log every payload before it enters CrewAI
- •Print inputs to agents, tasks, and tools.
- •If
JSON.stringify(payload)throws, you’ve found your culprit.
function safeLog(label: string, value: unknown) {
try {
console.log(label, JSON.stringify(value));
} catch (err) {
console.error(label, "is not serializable", err);
}
}
- •
Strip fields until the error disappears
- •Remove nested objects first.
- •Then remove dates, SDK clients, ORM entities, and custom classes.
- •Re-add fields one by one until the failure returns.
- •
Validate all inputs with a schema
- •Use Zod or similar before handing data to CrewAI.
- •Reject anything that is not plain JSON early.
import { z } from "zod";
const TaskInputSchema = z.object({
customerId: z.string(),
createdAt: z.string(),
});
const parsed = TaskInputSchema.parse(input);
Prevention
- •
Keep CrewAI boundaries boring:
- •plain objects only
- •strings only for tool I/O when possible
- •no class instances or live clients in task state
- •
Normalize everything before handing it to an agent:
- •convert
Dateto ISO strings - •convert decimals/IDs to strings if needed
- •parse JSON once at the edge and keep it parsed internally
- •convert
- •
Add a serialization test in CI:
expect(() => JSON.stringify(taskInput)).not.toThrow();
If you treat CrewAI inputs and outputs like API contracts instead of loose JS objects, this error stops showing up during scaling runs.
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