ComposioHQ/composio · error · Error
experimental_subAgent() expected valid JSON output for struc
Error message
experimental_subAgent() expected valid JSON output for structured response.
What it means
When a schema is configured, experimental_subAgent() expects the subagent's trimmed final text to be parseable JSON (tryParseStructuredJson). If parsing returns undefined — the text is not valid JSON — this error is thrown in finalizeInvokeAgentText.
Source
Thrown at ts/packages/cli/src/services/run-subagent-shared.ts:394
}
return bestCandidate?.value;
};
export const finalizeInvokeAgentText = (
text: string,
options: InvokeAgentNormalizedOptions
): Pick<InvokeAgentResponse, 'result' | 'structuredOutput'> => {
const trimmed = text.trim();
if (!options.structuredSchema) {
return {
result: trimmed,
};
}
const parsed = tryParseStructuredJson(trimmed);
if (parsed === undefined) {
throw new Error('experimental_subAgent() expected valid JSON output for structured response.');
}
return {
result: null,
structuredOutput: validateStructuredOutput(parsed, options),
};
};
View on GitHub (pinned to 64b1b85502)
Solutions
- Make the prompt explicitly require raw JSON only, with no prose or code fences
- Retry the call — nondeterministic models sometimes emit prose intermittently
- Reduce output size or simplify the schema to avoid truncation
- If the model wraps output in fences, instruct it not to, since the parser does not strip them
Example fix
// before
await experimental_subAgent('Summarize this repo', { schema });
// after
await experimental_subAgent('Summarize this repo. Respond with ONLY raw JSON matching the schema — no prose, no markdown fences.', { schema }); Defensive patterns
Strategy: retry
Validate before calling
const looksLikeJson = (s: string) => { try { JSON.parse(s); return true; } catch { return false; } }; Type guard
const looksLikeJson = (s: string): boolean => { try { JSON.parse(s); return true; } catch { return false; } }; Try / catch
catch (e) { if (e instanceof Error && e.message.includes('valid JSON output')) { return await experimental_subAgent(prompt + ' Output ONLY raw JSON.', { schema }); } throw e; } Prevention
- State 'respond with only raw JSON, no fences' in every structured prompt
- Retry: JSON compliance is nondeterministic
- Strip nothing yourself — the parser does not remove fences, so prevent them via prompt
When it happens
Trigger: experimental_subAgent(prompt, { schema }) where the agent replies with prose, markdown-fenced JSON that is not extracted, truncated JSON, or leading chatter like 'Here is the result: {...}'.
Common situations: Prompts that do not explicitly demand JSON-only output, models wrapping JSON in ```json fences or commentary, long outputs hitting token limits and getting truncated, or the schema not being conveyed to the subagent.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- Tool arguments were provided as a string that is not valid J
- experimental_subAgent() structured output failed schema vali
- experimental_subAgent() target must be "claude", "codex", or
- experimental_subAgent() requires Zod 4 with z.toJSONSchema()
- experimental_subAgent() schema must be a Zod schema or JSON
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/c22ea28873029e0d.
Report an issue: GitHub.