paperclipai/paperclip · error

runner_prp_command_missing

runner_prp_command_missing

Error message

runner_prp_command_missing:${commandId}

What it means

Inside waitForCommand, the coordinator polls authority.commandOutcome(commandId) every 10ms. If the authority has no record of the given commandId at all, it throws 'runner_prp_command_missing:<id>' immediately rather than waiting for the timeout. This means the command was never queued through this session's authority, or the outcome record was discarded (e.g. after a disconnect/rebind that cleared pending command state).

Source

Thrown at server/src/services/native-runtime/runner-prp-coordinator.ts:403

              terminalEvent,
              new Promise<never>((_resolve, reject) => {
                timer = setTimeout(
                  () => reject(new Error("runner_prp_terminal_timeout")),
                  timeoutMs,
                );
                timer.unref();
              }),
            ]);
          } finally {
            if (timer) clearTimeout(timer);
          }
        },
        waitForCommand: async (commandId, timeoutMs = 30_000) => {
          if (released) throw new Error("runner_prp_session_released");
          const deadline = Date.now() + timeoutMs;
          while (Date.now() < deadline) {
            const outcome = authority.commandOutcome(commandId);
            if (!outcome) throw new Error(`runner_prp_command_missing:${commandId}`);
            if (outcome.status === "completed") return outcome.result;
            if (outcome.status === "failed" || outcome.status === "rejected") {
              const message = outcome.result && typeof outcome.result.message === "string"
                ? outcome.result.message
                : `runner_prp_command_${outcome.status}:${commandId}`;
              throw new Error(message);
            }
            await new Promise<void>((resolve) => {
              const timer = setTimeout(resolve, 10);
              timer.unref();
            });
          }
          throw new Error(`runner_prp_command_timeout:${commandId}`);
        },
        waitForGoalEvent: async (requestId, timeoutMs = 30_000) => {
          if (released) throw new Error("runner_prp_session_released");
          if (observedGoalRequests.has(requestId)) {
            const error = observedGoalRequests.get(requestId);

View on GitHub (pinned to 01ad858492)

Solutions

  1. Confirm the commandId came from the return value of session.queueCommand on the SAME session instance before waiting on it.
  2. Log/inspect authority.commandOutcome(commandId) (or the command registry) to see whether the id exists at all; if the state was reset, re-queue the command.
  3. Catch /runner_prp_command_missing:(.+)/, extract the id, and treat it as a permanent failure — do not retry the wait, re-issue the command instead.
  4. Align id generation: ensure caller and coordinator share the same id namespace (queueCommand's optional commandId parameter must match what waitForCommand receives).

Example fix

// before
const { commandId } = session.queueCommand('question', payload, myOwnId);
await session.waitForCommand(myOwnId); // wrong id source

// after
const { commandId } = session.queueCommand('question', payload);
await session.waitForCommand(commandId);
Defensive patterns

Strategy: validation

Validate before calling

// Wait only on ids obtained from this session's queueCommand:
const { commandId } = session.queueCommand(type, payload);
// optional assertion before waiting:
if (typeof commandId !== 'string' || !commandId) throw new Error('commandId required from queueCommand');

Try / catch

try {
  return await session.waitForCommand(commandId, 30_000);
} catch (e) {
  const m = /^runner_prp_command_missing:(.+)$/.exec(e.message);
  if (m) {
    // unknown id: re-queue instead of retrying the wait
    const cmd = session.queueCommand(type, payload);
    return session.waitForCommand(cmd.commandId, 30_000);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling waitForCommand with a commandId that was never returned by queueCommand on this session; a typo'd or truncated id; calling waitForCommand for a command queued on a previous session whose authority state was reset after reconnect; passing a controller-generated id that was never registered with the authority.

Common situations: Persisting commandIds in a DB and replaying waitForCommand after a server restart; mismatched id formats between caller and authority (e.g. prefix added/removed across versions); assuming waitForCommand waits for any command instead of the specific pre-registered one.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/c7bdad7d3b532759. Report an issue: GitHub.