ComposioHQ/composio · error · Error
Expected a z.object() schema.
Error message
Expected a z.object() schema.
What it means
zodObjectSchemaToJsonSchema only converts Zod object schemas; passing a ZodString, ZodArray, z.union, z.any, or a wrapped/refined non-object schema throws this plain Error. Conversion to JSON Schema parameters requires a top-level object because tool parameters are named-key maps.
Source
Thrown at ts/packages/core/src/utils/zodSchema.ts:78
// Mirror the v4 `io` mode on the v3 converter so the two runtimes serialize `.default()`,
// `.transform()` and `.pipe()` schemas consistently at this boundary.
const converted = zodToJsonSchema.default(schema, {
name,
pipeStrategy: mode,
effectStrategy: mode === 'input' ? 'input' : 'any',
});
return stripSchemaKeyword(getNamedDefinition(converted, name));
};
export const zodObjectSchemaToJsonSchema = (
schema: AnyZodSchema,
name: string = 'schema',
mode: ZodJsonSchemaMode = 'input'
): ObjectJsonSchema => {
if (!isZodObjectSchema(schema)) {
throw new Error('Expected a z.object() schema.');
}
// The schema is a confirmed object and getNamedDefinition guarantees a well-formed conversion,
// so the result always carries `properties` (and `required` only when there are required keys).
const jsonSchema = zodSchemaToJsonSchema(schema, name, mode);
return {
type: 'object',
properties: (jsonSchema.properties as Record<string, unknown>) ?? {},
...(jsonSchema.required ? { required: jsonSchema.required as string[] } : {}),
};
};
View on GitHub (pinned to 64b1b85502)
Solutions
- Ensure the top-level schema is z.object({...}) or its variants (.strict(), .passthrough(), .loose())
- Move refinements to runtime validation elsewhere, or use z.object(...).superRefine only if the converter supports effects — otherwise validate inside the tool body
- For union inputs, model as z.object with a discriminator field or a string field with allowed values
Example fix
// before
const params = z.union([z.object({ id: z.string() }), z.object({ name: z.string() })]);
// after
const params = z.object({ id: z.string().optional(), name: z.string().optional() }); Defensive patterns
Strategy: type-guard
Validate before calling
import { z, ZodFirstPartyTypeKind } from 'zod';
const isZodObject = (s: any): s is z.ZodObject<any> => s?._def?.typeName === ZodFirstPartyTypeKind.ZodObject;
if (!isZodObject(schema)) throw new Error('Provide a z.object() schema'); Type guard
function isZodObjectSchema(s: unknown): s is z.ZodObject<z.ZodRawShape> { return s instanceof z.ZodObject; } Try / catch
try { zodObjectSchemaToJsonSchema(schema); } catch (e) { if ((e as Error).message === 'Expected a z.object() schema.') { /* restructure schema */ } throw e; } Prevention
- Top-level tool parameter schemas must be z.object(...)
- Avoid .refine()/.transform() wrappers at the top level
- Use discriminated fields instead of top-level unions
When it happens
Trigger: Passing anything other than a z.object(...) (or .strict()/.passthrough() variant) as a tool's parameter schema to zodObjectSchemaToJsonSchema — e.g. z.record(z.string()), z.union([...]), or a ZodEffects object from .refine().
Common situations: Defining tool schemas as unions/records that look object-like; wrapping with .refine()/.transform() producing ZodEffects; migrating from a converter that accepted any schema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- schema is unsatisfiable (JSON Schema `false`)
- {error.message}
- Unrecognized key(s) in object: {', '.join(repr(key) for key
- experimental_subAgent() schema must be a Zod schema or JSON
- Invalid arguments for local tool ${resolution.finalSlug}: ${
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/b796cce8c96143e7.
Report an issue: GitHub.