can1357/oh-my-pi · error
send requires data or signal
Error message
send requires data or signal
What it means
A send operation must carry something to deliver: either data (stdin/pty input) or a signal. DaemonBroker throws this fixed-message error when operation.data and operation.signal are both undefined, since there is nothing to do. It is a request-validation guard in #send.
Source
Thrown at packages/coding-agent/src/launch/broker.ts:1117
`Daemon ${operation.name} generation ${boundGeneration} exited${exit}; ` +
"the wait was rejected instead of continuing against a replacement generation",
);
}
// A for:"ready" wait that woke on a terminal exit without ever observing
// readiness is still "not ready" — surface it as timed out so callers and the
// renderer don't chain work against a dead process.
const timedOut = operation.for === "ready" && !pattern ? !readyObserved() : !woke;
return { op: "wait", daemon: record.snapshot, matched, timedOut };
}
async #send(operation: Extract<DaemonOperation, { op: "send" }>): Promise<DaemonRpcResult> {
const record = this.#record(operation.name);
await this.#refreshDetached(record);
if (terminalState(record.snapshot.state) || record.snapshot.state === "stopping") {
throw new Error(`Daemon ${operation.name} is ${record.snapshot.state}`);
}
if (operation.data === undefined && operation.signal === undefined) {
throw new Error("send requires data or signal");
}
if (operation.data !== undefined) {
if (record.pty) record.pty.write(operation.data);
else if (record.input) {
record.input.write(operation.data);
await record.input.flush();
} else throw new Error(`Daemon ${operation.name} stdin is unavailable`);
}
if (operation.signal) {
if (process.platform === "win32" && record.pty) {
if (operation.signal === "SIGINT") record.pty.write("\u0003");
else record.pty.kill();
} else {
const processRef = record.snapshot.pid === undefined ? null : Process.fromPid(record.snapshot.pid);
if (!processRef) throw new Error(`Daemon ${operation.name} process is unavailable`);
processRef.killTree(SIGNAL_NUMBER[operation.signal]);
}
}View on GitHub (pinned to 9690622007)
Solutions
- Provide the data string you intended to write to the daemon's stdin/pty.
- Provide the signal you intended to deliver (e.g. "SIGINT").
- Guard the call site: only issue a send op when at least one of data/signal is defined.
Example fix
// before
const op = { op: "send", name: "repl" }; // data lost in refactor
// after
const op = { op: "send", name: "repl", data: "run()\n" }; Defensive patterns
Strategy: validation
Validate before calling
if (op.data === undefined && op.signal === undefined) {
throw new Error("send op needs data or signal");
} Type guard
function isDeliverableSend(op: { data?: string; signal?: string }): boolean {
return op.data !== undefined || op.signal !== undefined;
} Try / catch
try {
await broker.send(op);
} catch (err) {
if (err instanceof Error && err.message === "send requires data or signal") {
// caller bug: reconstruct the op with a payload
} else throw err;
} Prevention
- Build send ops through a helper function that requires at least one of data/signal at the type level.
- Avoid spreading conditional objects that can silently drop the data field.
- Cover the send call site with a test that asserts a payload is always present.
When it happens
Trigger: Calling send with an empty payload — e.g. { op: "send", name: "x" } with neither data nor signal, or data explicitly set to undefined after conditional construction.
Common situations: Code that builds the send op conditionally (`...(cond ? { data } : {})`) where cond was false; deserialized RPC requests that dropped empty-string fields; wiring bugs passing the wrong variable.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Gemini Files API delete requires a valid file name
- maxAgents must be a positive integer
- Unsupported vault:// file op: ${rawOp}
- Unsupported vault:// vault op: ${rawOp}
- vault:// path resolution only supports plain filesystem path
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/4d2b32b25c361d4a.
Report an issue: GitHub.