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

  1. Make the prompt explicitly require raw JSON only, with no prose or code fences
  2. Retry the call — nondeterministic models sometimes emit prose intermittently
  3. Reduce output size or simplify the schema to avoid truncation
  4. 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

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


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/c22ea28873029e0d. Report an issue: GitHub.