can1357/oh-my-pi · error

operation.for must be ready or exit

Error message

operation.for must be ready or exit

What it means

parseDaemonOperation validates the `wait` operation's `for` field, which must be the literal string "ready" or "exit". Any other value is rejected because the broker can only wait on those two daemon lifecycle states.

Source

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

			};
		case "logs":
			return {
				op,
				name: stringValue(source.name, "operation.name"),
				lines: numberValue(source.lines, "operation.lines"),
				head: booleanValue(source.head, "operation.head"),
				grep: optionalString(source.grep, "operation.grep"),
				follow: booleanValue(source.follow, "operation.follow"),
				cursor: optionalNumber(source.cursor, "operation.cursor"),
				renderTerminalRows:
					source.renderTerminalRows === undefined
						? undefined
						: booleanValue(source.renderTerminalRows, "operation.renderTerminalRows"),
				timeoutMs: numberValue(source.timeoutMs, "operation.timeoutMs"),
			};
		case "wait": {
			const target = stringValue(source.for, "operation.for");
			if (target !== "ready" && target !== "exit") throw new Error("operation.for must be ready or exit");
			return {
				op,
				name: stringValue(source.name, "operation.name"),
				for: target,
				pattern: optionalString(source.pattern, "operation.pattern"),
				timeoutMs: numberValue(source.timeoutMs, "operation.timeoutMs"),
			};
		}
		case "send":
			return {
				op,
				name: stringValue(source.name, "operation.name"),
				data: optionalString(source.data, "operation.data"),
				signal: source.signal === undefined ? undefined : daemonSignal(source.signal),
			};
		case "stop":
			return {
				op,

View on GitHub (pinned to 9690622007)

Solutions

  1. Set `for` to exactly "ready" or "exit" in the request.
  2. Check protocol.ts for the current set of supported wait targets.
  3. Align client and daemon versions so both agree on operation fields.
  4. If a new wait target is needed, extend parseDaemonOperation in protocol.ts and regenerate/rebuild.

Example fix

// before
{ "op": "wait", "for": "started", "name": "main", "timeoutMs": 5000 }
// after
{ "op": "wait", "for": "ready", "name": "main", "timeoutMs": 5000 }
Defensive patterns

Strategy: validation

Validate before calling

const VALID_WAIT_TARGETS = ["ready", "exit"] as const;
function buildWaitOp(forTarget: string) {
  if (!VALID_WAIT_TARGETS.includes(forTarget as any)) throw new Error(`invalid wait target: ${forTarget}`);
  return { op: "wait", for: forTarget };
}

Type guard

const isValidWaitTarget = (v: unknown): v is "ready" | "exit" => v === "ready" || v === "exit";

Try / catch

try {
  await broker.request({ op: "wait", for: target, name, timeoutMs });
} catch (err) {
  if (err.message.includes("operation.for must be")) throw new Error(`bad wait target "${target}"; use ready|exit`);
  throw err;
}

Prevention

When it happens

Trigger: Sending a daemon wire request with op "wait" and `for` set to anything other than "ready"/"exit" — e.g. "started", "stopped", missing field, or a typo.

Common situations: Hand-written RPC payloads against the daemon socket, scripts copied from an older protocol version where other wait targets existed, or a client/daemon version skew.

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