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

  1. Ensure the top-level schema is z.object({...}) or its variants (.strict(), .passthrough(), .loose())
  2. Move refinements to runtime validation elsewhere, or use z.object(...).superRefine only if the converter supports effects — otherwise validate inside the tool body
  3. 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

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


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