{"record":{"id":"336f08d1aedd3133","repo":"can1357/oh-my-pi","slug":"label-must-be-a-string","errorCode":null,"errorMessage":"${label} must be a string","messagePattern":"(.+?) must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/launch/protocol.ts","lineNumber":162,"sourceCode":"}\n\nexport type DaemonWireMessage = DaemonWireResponse | DaemonCompletionNotification;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction record(value: unknown, label: string): Record<string, unknown> {\n\tif (!isRecord(value)) throw new Error(`${label} must be an object`);\n\treturn value;\n}\n\nfunction stringValue(value: unknown, label: string): string {\n\tif (typeof value !== \"string\" || value.length === 0) throw new Error(`${label} must be a non-empty string`);\n\treturn value;\n}\nfunction rawString(value: unknown, label: string): string {\n\tif (typeof value !== \"string\") throw new Error(`${label} must be a string`);\n\treturn value;\n}\n\nfunction optionalString(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn stringValue(value, label);\n}\n\nfunction optionalRawString(value: unknown, label: string): string | undefined {\n\tif (value === undefined) return undefined;\n\treturn rawString(value, label);\n}\n\nfunction booleanValue(value: unknown, label: string): boolean {\n\tif (typeof value !== \"boolean\") throw new Error(`${label} must be a boolean`);\n\treturn value;\n}\n","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/launch/protocol.ts#L144-L180","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","solutions":["Inspect the label in the message to find which field is not a string","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)","If the field is genuinely optional, have the producer omit it and parse with optionalRawString instead","Check daemon/client version mismatch and align both sides on the same wire schema"],"exampleFix":"// before\nparseDaemonSpec({ id: 42, command: [\"sleep\"] })\n// after\nparseDaemonSpec({ id: \"42\", command: [\"sleep\"] })","handlingStrategy":"validation","validationCode":"function isPlainObject(v: unknown): v is Record<string, unknown> { return typeof v === \"object\" && v !== null; }\nfunction assertStringFields(obj: unknown, fields: string[]): void {\n  if (!isPlainObject(obj)) throw new Error(\"payload must be an object\");\n  for (const f of fields) {\n    const v = obj[f];\n    if (typeof v !== \"string\") throw new Error(`field '${f}' must be a string, got ${typeof v}`);\n  }\n}\n// before calling: assertStringFields(payload, [\"id\", \"commandLabel\"]);","typeGuard":"function isString(v: unknown): v is string { return typeof v === \"string\"; }","tryCatchPattern":"try {\n  const spec = parseDaemonSpec(payload);\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"must be a string\")) {\n    // log payload field types and reject/repair the payload\n  } else throw err;\n}","preventionTips":["Validate wire payloads against a JSON schema at the producer, not just the consumer","Never serialize undefined/null for required string fields — omit or default them","Add a shared type/interface between producer and consumer and typecheck both sides","Version the wire protocol and gate parsing on a protocolVersion field"],"tags":["validation","ipc","protocol","type-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}