{"record":{"id":"8b9e34bc5f3359d1","repo":"paperclipai/paperclip","slug":"runner-prp-command-missing-command-commandid","errorCode":null,"errorMessage":"runner_prp_command_missing:${command.commandId}","messagePattern":"runner_prp_command_missing:(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/realtime/runner-prp-ws.ts","lineNumber":208,"sourceCode":"  const binding = registrations.get(current.runId);\n  if (!binding || binding.generation !== current.generation) return null;\n  const runId = current.runId;\n  const command = binding.authority.queueCommand(\n    input.type,\n    input.payload ?? {},\n    input.commandId,\n    true,\n  );\n  return {\n    runId,\n    commandId: command.commandId,\n    controllerSeq: command.controllerSeq,\n    completion: (async () => {\n      const deadline = Date.now() + 30_000;\n      while (Date.now() < deadline) {\n        const outcome = binding.authority.commandOutcome(command.commandId);\n        if (!outcome) {\n          throw new Error(`runner_prp_command_missing:${command.commandId}`);\n        }\n        if (outcome.status === \"completed\") return outcome.result;\n        if (outcome.status === \"failed\" || outcome.status === \"rejected\") {\n          const message =\n            outcome.result && typeof outcome.result.message === \"string\"\n              ? outcome.result.message\n              : `runner_prp_command_${outcome.status}:${command.commandId}`;\n          throw new Error(message);\n        }\n        await new Promise<void>((resolve) => {\n          const timer = setTimeout(resolve, 10);\n          timer.unref();\n        });\n      }\n      throw new Error(`runner_prp_command_timeout:${command.commandId}`);\n    })(),\n  };\n}","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/realtime/runner-prp-ws.ts#L190-L226","documentation":"Thrown by queueLiveRunnerPrpCommand when, after the command is queued on the live binding, the authority's commandOutcome lookup returns nothing for the commandId within the polling loop — i.e. the command was never registered or was dropped before producing an outcome. The message carries the missing commandId.","triggerScenarios":"Calling steer/nativeControl on a live runner binding whose authority lost or never recorded the command (e.g. authority re-registered between queueing and outcome lookup, command id mismatch).","commonSituations":"Runner reconnected mid-command so the old authority's outcome map is gone; bug dropping the command before registration; stale binding used after reconnect.","solutions":["Verify the command was accepted/registered by the authority before polling its outcome","Re-acquire the current authority binding and resend the command with a new commandId","Handle runner reconnects: invalidate in-flight commands on re-registration","Check for race between queueLiveRunnerPrpCommand and authority re-registration"],"exampleFix":"// before\nawait queueLiveRunnerPrpCommand(binding, command); // throws runner_prp_command_missing\n// after\ntry {\n  await queueLiveRunnerPrpCommand(binding, command);\n} catch (e) {\n  if (String(e.message).startsWith('runner_prp_command_missing')) {\n    const fresh = getLiveBinding(command.runId);\n    return queueLiveRunnerPrpCommand(fresh, { ...command, commandId: newId() });\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"if (!getLiveBinding(command.runId) || binding.generation !== currentGeneration) await reacquireBinding();","typeGuard":null,"tryCatchPattern":"try { await queueLiveRunnerPrpCommand(binding, cmd) } catch (e) { if (String(e.message).startsWith('runner_prp_command_missing')) { return resendOnFreshBinding(cmd); } throw e; }","preventionTips":["Invalidate in-flight commands when an authority re-registers","Confirm command registration before entering the outcome polling loop","Re-fetch the current binding instead of caching one across reconnects","Generate fresh commandIds on resend to avoid stale outcome lookups"],"tags":["websocket","command","race"],"backgroundTag":"resource-not-found","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}