can1357/oh-my-pi · error

${label} must be a string

Error message

${label} must be a string

What it means

This error is thrown by rawString(), the strict string validator in the daemon launch protocol parser. It fires whenever a field decoded from daemon wire JSON (spec, request, snapshot, or RPC result) is not a string. It exists to fail fast on malformed IPC payloads instead of letting non-string values propagate into daemon state.

Source

Thrown at packages/coding-agent/src/launch/protocol.ts:162

}

export type DaemonWireMessage = DaemonWireResponse | DaemonCompletionNotification;

function isRecord(value: unknown): value is Record<string, unknown> {
	return typeof value === "object" && value !== null && !Array.isArray(value);
}

function record(value: unknown, label: string): Record<string, unknown> {
	if (!isRecord(value)) throw new Error(`${label} must be an object`);
	return value;
}

function stringValue(value: unknown, label: string): string {
	if (typeof value !== "string" || value.length === 0) throw new Error(`${label} must be a non-empty string`);
	return value;
}
function rawString(value: unknown, label: string): string {
	if (typeof value !== "string") throw new Error(`${label} must be a string`);
	return value;
}

function optionalString(value: unknown, label: string): string | undefined {
	if (value === undefined) return undefined;
	return stringValue(value, label);
}

function optionalRawString(value: unknown, label: string): string | undefined {
	if (value === undefined) return undefined;
	return rawString(value, label);
}

function booleanValue(value: unknown, label: string): boolean {
	if (typeof value !== "boolean") throw new Error(`${label} must be a boolean`);
	return value;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Inspect the label in the message to find which field is not a string
  2. Fix the producer of the payload to emit a non-empty string for that field (empty strings are allowed here, only non-strings rejected — for empty rejection use stringValue)
  3. If the field is genuinely optional, have the producer omit it and parse with optionalRawString instead
  4. Check daemon/client version mismatch and align both sides on the same wire schema

Example fix

// before
parseDaemonSpec({ id: 42, command: ["sleep"] })
// after
parseDaemonSpec({ id: "42", command: ["sleep"] })
Defensive patterns

Strategy: validation

Validate before calling

function isPlainObject(v: unknown): v is Record<string, unknown> { return typeof v === "object" && v !== null; }
function assertStringFields(obj: unknown, fields: string[]): void {
  if (!isPlainObject(obj)) throw new Error("payload must be an object");
  for (const f of fields) {
    const v = obj[f];
    if (typeof v !== "string") throw new Error(`field '${f}' must be a string, got ${typeof v}`);
  }
}
// before calling: assertStringFields(payload, ["id", "commandLabel"]);

Type guard

function isString(v: unknown): v is string { return typeof v === "string"; }

Try / catch

try {
  const spec = parseDaemonSpec(payload);
} catch (err) {
  if (err instanceof Error && err.message.includes("must be a string")) {
    // log payload field types and reject/repair the payload
  } else throw err;
}

Prevention

When it happens

Trigger: Calling parseDaemonSpec, parseDaemonWireRequest, parseDaemonOperation, or parseDaemonRpcResult with a payload where a required field (e.g. spec id, command args item, rpc result field) is undefined, null, a number, or an object instead of a string. Also thrown indirectly by stringArray/stringRecord when an array item or record value is not a string (message becomes '<label> item must be a string').

Common situations: Hand-written daemon config JSON with a missing or mistyped field; an older daemon binary writing a wire format that changed; a client sending a numeric PID or port where a string id is expected; JSON round-tripping that turned a string into a nested object.

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 can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/336f08d1aedd3133. Report an issue: GitHub.