Skip to content

Tool schemas don't support z.union (requires type: object) #62

Description

@dremnik

Problem

When using z.union() for tool parameters, the schema fails validation:

[kernl] Invalid schema for function 'supermemory_documents_add': schema must be a JSON Schema of 'type: "object"', got 'type: "None"'.

Example

This pattern is useful for mutually exclusive parameters:

export const add = tool({
  id: "supermemory_documents_add",
  parameters: z.union([
    z.object({
      content: z.string().describe("Plaintext content"),
      metadata: MetadataSchema,
    }),
    z.object({
      url: z.url().describe("URL to ingest"),
      metadata: MetadataSchema,
    }),
  ]),
  // ...
});

Current Workaround

Use a single object with optional fields and a .refine() for validation:

parameters: z
  .object({
    content: z.string().optional().describe("Plaintext (use this OR url)"),
    url: z.string().url().optional().describe("URL (use this OR content)"),
    metadata: MetadataSchema,
  })
  .refine((data) => Boolean(data.content) !== Boolean(data.url), {
    message: "Provide either content or url, not both",
  }),

Potential Solutions

  1. Transform unions to anyOf/oneOf - Some model providers support oneOf in JSON Schema
  2. Flatten unions - If all union members are objects, merge their properties with optional markers
  3. Better error message - At minimum, surface a clearer error explaining the limitation

Context

Discovered while building the Supermemory toolkit where documents can be added via plaintext content OR URL, but not both.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions