ComposioHQ/composio · error · ComposioInvalidToolArgumentsError
${describeTool(toolSlug)} expected arguments to be an object
Error message
${describeTool(toolSlug)} expected arguments to be an object, received ${actual} What it means
Thrown by assertPlainObject inside normalizeToolArguments when tool arguments are neither a plain object nor a JSON string that parses to one. After normalization the SDK requires a Record<string, unknown>; arrays, primitives, or null are rejected with the actual received type in the message.
Source
Thrown at ts/packages/core/src/utils/toolArguments.ts:66
} catch (cause) {
throw new ComposioInvalidToolArgumentsError(
`${describeTool(toolSlug)} received arguments as a string that is not valid JSON`,
{ cause: cause instanceof Error ? cause : undefined }
);
}
return assertPlainObject(parsed, toolSlug);
}
return assertPlainObject(input, toolSlug);
}
function assertPlainObject(value: unknown, toolSlug?: string): Record<string, unknown> {
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
return value as Record<string, unknown>;
}
const actual = Array.isArray(value) ? 'array' : typeof value;
throw new ComposioInvalidToolArgumentsError(
`${describeTool(toolSlug)} expected arguments to be an object, received ${actual}`
);
}
function describeTool(toolSlug?: string): string {
return toolSlug ? `Tool '${toolSlug}'` : 'Tool';
}
View on GitHub (pinned to 64b1b85502)
Solutions
- Pass a plain object matching the tool's inputParameters schema
- If the caller supplies a JSON string, ensure it parses to an object (not array/scalar) and is not double-stringified
- Catch ComposioInvalidToolArgumentsError and map it to a model-facing retry with the expected schema
Example fix
// before
await executeTool('foo', 'not json');
// after
await executeTool('foo', { query: 'not json' }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalize(args: unknown): Record<string, unknown> | null { if (typeof args === 'string') { try { args = JSON.parse(args); } catch { return null; } } return (typeof args === 'object' && args !== null && !Array.isArray(args)) ? args as Record<string, unknown> : null; } Type guard
const isPlainObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
Try / catch
catch (e) { if (e instanceof ComposioInvalidToolArgumentsError) return { error: e.message }; throw e; } Prevention
- Match your argument shape to the tool's inputParameters schema
- Beware double-encoded JSON strings
- Reject arrays/primitives before calling executeTool
When it happens
Trigger: Calling executeTool with args[0] = [], 42, "literal text", null, or a JSON string like '"hi"' / '[1,2]' that parses to a non-object; also double-encoded strings like '"{\"a\":1}"'.
Common situations: Model emits a bare string or array as tool input; agent framework forwards positional args; tool schema expects object but caller passes a list of positional values.
Related errors
- ${describeTool(toolSlug)} received arguments as a string tha
- {error.message}
- Unrecognized key(s) in object: {', '.join(repr(key) for key
- experimental_subAgent() target must be "claude", "codex", or
- Invalid Composio CLI release tag: ${releaseTag}
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/4d72c60a02c3523e.
Report an issue: GitHub.