coleam00/Archon · error

native tool schema: enum for '${key}' must be non-empty stri

Error message

native tool schema: enum for '${key}' must be non-empty strings

What it means

When converting an enum property in a tool's inputSchema, jsonSchemaToTypeBox filters the enum values to strings; if nothing survives (the enum is empty or contains no strings) it throws. Only string enums can be represented as TypeBox literal unions for Pi native tools.

Source

Thrown at packages/providers/src/community/pi/native-tools.ts:34

  if (
    schema.type !== 'object' ||
    typeof schema.properties !== 'object' ||
    schema.properties === null
  ) {
    throw new Error('native tool inputSchema must be an object schema with `properties`');
  }
  const props = schema.properties as Record<string, Record<string, unknown>>;
  const required = new Set(
    Array.isArray(schema.required) ? (schema.required as unknown[]).filter(isString) : []
  );

  const shape: Record<string, TSchema> = {};
  for (const [key, prop] of Object.entries(props)) {
    let field: TSchema;
    if (Array.isArray(prop.enum)) {
      const values = prop.enum.filter(isString);
      if (values.length === 0) {
        throw new Error(`native tool schema: enum for '${key}' must be non-empty strings`);
      }
      field = Type.Union(values.map(v => Type.Literal(v)));
    } else if (prop.type === 'string') {
      field = Type.String();
    } else if (prop.type === 'boolean') {
      field = Type.Boolean();
    } else {
      throw new Error(
        `native tool schema: unsupported type for '${key}' (only string / string-enum / boolean)`
      );
    }
    if (typeof prop.description === 'string') {
      field = Type.Unsafe<unknown>({ ...field, description: prop.description });
    }
    shape[key] = required.has(key) ? field : Type.Optional(field);
  }
  return Type.Object(shape);
}

View on GitHub (pinned to 0773b97458)

Solutions

  1. Ensure every enum member is a string: `enum: ['low', 'high']`
  2. Replace a numeric enum with string literals
  3. If values are dynamic, use `type: 'string'` and validate in the tool handler instead of `enum`

Example fix

// before
{ type: 'object', properties: { level: { type: 'number', enum: [1, 2] } } }
// after
{ type: 'object', properties: { level: { enum: ['low', 'high'] } } }
Defensive patterns

Strategy: validation

Validate before calling

for (const [key, prop] of Object.entries(schema.properties)) {
  if (Array.isArray(prop.enum) && prop.enum.filter(v => typeof v === 'string').length === 0) {
    throw new Error(`property '${key}' has an empty or non-string enum`);
  }
}

Type guard

function hasValidStringEnum(prop: unknown): prop is { enum: string[] } {
  return typeof prop === 'object' && prop !== null && Array.isArray((prop as any).enum)
    && (prop as any).enum.every((v: unknown) => typeof v === 'string') && (prop as any).enum.length > 0;
}

Try / catch

try {
  registerNativeTool(tool);
} catch (err) {
  if (err.message.includes("enum for '")) {
    console.error(`Fix enum values on tool '${tool.name}': all members must be non-empty strings`);
  }
  throw err;
}

Prevention

When it happens

Trigger: inputSchema property with `enum: []`, or `enum: [1, 2, 3]` / `[true]` containing no string values, passed to buildPiNativeToolDefinitions.

Common situations: Numeric enums ported from OpenAPI specs, empty placeholder enums, or enums with mixed types where non-string members are silently dropped and an all-non-string enum trips the error.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/93ea01bc97394b3d. Report an issue: GitHub.