can1357/oh-my-pi · error · TypeError
Cannot convert a symbol to a string
Error message
Cannot convert a symbol to a string
What it means
omptype's JSON Schema emitter builds string-keyed JSON Schema objects, and JSON Schema has no representation for symbol-keyed properties. When emitObject encounters a property whose key is a symbol it cannot name it in the `properties` map, so it throws a TypeError with the engine's native 'Cannot convert a symbol to a string' message (triggered by `String(prop.key)`).
Source
Thrown at packages/omptype/src/json-schema.ts:280
default:
return undefined;
}
}
function emitObject(
props: PropIR[],
index: IR | undefined,
extras: "keep" | "reject" | "delete",
ctx: EmitCtx,
): JsonSchema {
const properties: Record<string, unknown> = {};
const required: string[] = [];
const filled = (prop: PropIR): boolean => !prop.opt && (ctx.options?.io === "output" || !prop.hasDefault);
// ArkType emits required properties first (each group in declaration
// order); downstream wire consumers rely on that stable ordering.
const ordered = [...props.filter(filled), ...props.filter(prop => !filled(prop))];
for (const prop of ordered) {
if (typeof prop.key === "symbol") throw new TypeError("Cannot convert a symbol to a string");
const key = String(prop.key);
const propertySchema = emit(prop.val, ctx);
if (prop.hasDefault) {
propertySchema.default = prop.defFactory ? (prop.def as () => unknown)() : prop.def;
}
properties[key] = propertySchema;
if (filled(prop)) required.push(key);
}
const schema: JsonSchema = { type: "object", properties };
if (required.length > 0) schema.required = required;
if (index !== undefined) schema.additionalProperties = emit(index, ctx);
else if (extras === "reject") schema.additionalProperties = false;
return schema;
}
function isJsonValue(value: unknown, seen = new Set<object>()): boolean {
if (value === null || typeof value === "string" || typeof value === "boolean") return true;
if (typeof value === "number") return Number.isFinite(value);View on GitHub (pinned to 9690622007)
Solutions
- Remove the symbol-keyed property from the type definition or move it to a non-schema object.
- Filter symbol-keyed props before emitting, e.g. rebuild the object type with only string keys.
- If symbols are needed internally, keep them out of the IR (declare the wire shape and augment at runtime).
Example fix
// before
const T = type({ id: string, [metadataKey]: string });
T.toJsonSchema(); // throws
// after
const T = type({ id: string });
T.toJsonSchema(); // works Defensive patterns
Strategy: validation
Validate before calling
function hasOnlyStringKeys(t) {
// build the schema in a guard context
try { t.toJsonSchema(); return true; } catch { return false; }
}
// or preemptively on the raw object literal:
const symbolKeys = Object.getOwnPropertySymbols(raw).length > 0;
if (symbolKeys) throw new Error('remove symbol keys before schema generation'); Type guard
function isSymbolKeyed(obj) {
return Object.getOwnPropertySymbols(obj).length > 0;
} Try / catch
try {
const schema = T.toJsonSchema();
} catch (e) {
if (e instanceof TypeError && e.message.includes('symbol')) {
// fall back to a symbol-free variant of the type or skip schema export
} else throw e;
} Prevention
- Keep schema/types limited to JSON-representable (string-keyed) shapes; augment symbols at runtime outside the type.
- Lint against computed symbol keys in type-definition modules.
- Add a CI check that renders toJsonSchema() for every exported API type.
When it happens
Trigger: Calling `type.toJsonSchema()` (via `emit`) on a Type whose object type includes a symbol-keyed property, e.g. `type({ [Symbol.iterator]: ... })` or an object literal with a computed symbol key that survived into the PropIR.
Common situations: Adding well-known-symbol members (Symbol.asyncIterator, Symbol.toStringTag, custom registry symbols) to object schemas used as DTOs; spreading objects carrying internal symbol metadata into a type definition before schema generation.
Related errors
- Schema contains a circular object graph — cannot enforce str
- Schema node has no type, combinator, or $ref — cannot enforc
- rpc chunk sequence length mismatch
- Host tool "${name}" must provide a JSON Schema object
- Invalid ${scope} output schema: ${error}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/bffee5299c6d44eb.
Report an issue: GitHub.