can1357/oh-my-pi · error
${label} must be an object
Error message
${label} must be an object What it means
The daemon protocol parser validates every decoded payload structurally. record(value, label) is the generic object check used by parseDaemon* functions; any wire payload that is not a plain object (wrong type, null, array) fails with '<label> must be an object', where label names the offending field or message kind.
Source
Thrown at packages/coding-agent/src/launch/protocol.ts:153
/** Response envelope kept raw until matched with its pending operation. */
export type DaemonWireResponse = { id: string; ok: true; result: unknown } | { id: string; ok: false; error: string };
/** Unsolicited terminal completion sent to the socket that owns a daemon. */
export interface DaemonCompletionNotification {
event: "daemon-completed";
completionId: string;
owner: string;
daemon: DaemonSnapshot;
}
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 {View on GitHub (pinned to 9690622007)
Solutions
- Log the raw payload and label from the error to identify the malformed field
- Ensure the sender serializes messages as JSON objects matching the current DaemonWireMessage schema
- Align client and broker versions so both sides agree on message shapes
Example fix
// before
socket.write(JSON.stringify("ping"));
// after
socket.write(JSON.stringify({ op: "ping" })); Defensive patterns
Strategy: type-guard
Validate before calling
function assertPlainObject(v: unknown, label: string): asserts v is Record<string, unknown> {
if (typeof v !== 'object' || v === null || Array.isArray(v)) throw new Error(`${label} must be an object`);
} Type guard
function isPlainObject(v: unknown): v is Record<string, unknown> {
return typeof v === 'object' && v !== null && !Array.isArray(v);
} Try / catch
try {
const msg = parseDaemonWireMessage(raw);
} catch (err) {
if (err.message.endsWith('must be an object')) {
logger.warn('malformed daemon payload', { raw: String(raw).slice(0, 200) });
return;
}
throw err;
} Prevention
- Run payloads through protocol validators before writing to the socket
- Always serialize daemon messages as JSON objects, never scalars or arrays
- Version-check peers before exchanging new message shapes
When it happens
Trigger: Sending malformed JSON over the broker socket (e.g. a bare string/number/array where a message object is expected); an RPC result or spec field decoded as the wrong type; null entries in payload arrays.
Common situations: Manual JSON-RPC experimentation against the socket; provider/client version skew changing message shapes; serialization bugs writing non-object values into message fields.
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
- ${label} must be a non-empty string
- Pending daemon completion is not an event
- Auth broker response failed schema validation
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE must contain a JSON object
- OMP_AUTH_BROKER_ACCOUNT_POOL_FILE entry for ${provider} must
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/98a8f9e421813c35.
Report an issue: GitHub.