can1357/oh-my-pi · error

${label} must be a boolean

Error message

${label} must be a boolean

What it means

Thrown by booleanValue(), the strict boolean validator for daemon protocol payloads. Any field parsed as a boolean (e.g. 'detached' in a spec, operation flags, snapshot fields) that arrives as anything other than true/false raises this. It guards against truthy/falsy values leaking across the daemon IPC boundary.

Source

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

	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;
}

function numberValue(value: unknown, label: string): number {
	if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${label} must be a finite number`);
	return value;
}

function optionalNumber(value: unknown, label: string): number | undefined {
	if (value === undefined) return undefined;
	return numberValue(value, label);
}

function stringArray(value: unknown, label: string): string[] {
	if (!Array.isArray(value)) throw new Error(`${label} must be an array of strings`);
	const result: string[] = [];
	for (const item of value) result.push(rawString(item, `${label} item`));
	return result;

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the label in the message to identify the offending field
  2. Change the producer to emit a real JSON boolean (true/false)
  3. Convert numeric/string flags at the producer boundary (Boolean(value) or value === "true")
  4. If the field should be omittable, wrap with a default at the producer instead of sending undefined

Example fix

// before
parseDaemonSpec({ id: "d1", command: ["sleep", "1"], detached: 1 })
// after
parseDaemonSpec({ id: "d1", command: ["sleep", "1"], detached: true })
Defensive patterns

Strategy: validation

Validate before calling

function assertBooleanFields(obj: Record<string, unknown>, fields: string[]): void {
  for (const f of fields) {
    if (typeof obj[f] !== "boolean") throw new Error(`field '${f}' must be a boolean`);
  }
}
// normalize first: obj.detached = obj.detached === 1 || obj.detached === "true";

Type guard

function isBoolean(v: unknown): v is boolean { return typeof v === "boolean"; }

Try / catch

try {
  const spec = parseDaemonSpec(payload);
} catch (err) {
  if (err instanceof Error && err.message.includes("must be a boolean")) {
    // coerce 0/1 and "true"/"false" strings at the producer and retry once
  } else throw err;
}

Prevention

When it happens

Trigger: Passing a payload to parseDaemonSpec, parseDaemonWireRequest, parseDaemonOperation, parseDaemonSnapshot, or parseDaemonRpcResult where a boolean field is 0/1, "true" (string), null, or missing (undefined) instead of an actual boolean.

Common situations: Config files using yes/no or 0/1 for booleans; query-string or CLI parsing that yields strings; a producer serializing 'detached: null' after failed initialization; schema drift between daemon versions.

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/90327c0e85062cf8. Report an issue: GitHub.