{"record":{"id":"85fa2a3c38d1637b","repo":"paperclipai/paperclip","slug":"runner-prp-authority-already-registered","errorCode":null,"errorMessage":"runner_prp_authority_already_registered","messagePattern":"runner_prp_authority_already_registered","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/realtime/runner-prp-ws.ts","lineNumber":131,"sourceCode":"    },\n  );\n}\n\nexport async function registerRunnerPrpAuthority(input: {\n  readonly companyId: string;\n  readonly issueId?: string;\n  readonly agentId?: string;\n  readonly runId: string;\n  readonly authority: DurablePrpControlPlane;\n}): Promise<{ readonly connectUrl: string; release(): Promise<void> }> {\n  if (loopbackOrigin === null) {\n    throw new Error(\"runner_prp_websocket_server_not_configured\");\n  }\n  if (!UUID_PATTERN.test(input.runId) || input.companyId.length === 0) {\n    throw new Error(\"runner_prp_authority_binding_invalid\");\n  }\n  if (registrations.has(input.runId)) {\n    throw new Error(\"runner_prp_authority_already_registered\");\n  }\n  const generation = Symbol(input.runId);\n  const registeredAuthority: RegisteredAuthority = {\n    companyId: input.companyId,\n    issueId: input.issueId ?? null,\n    agentId: input.agentId ?? null,\n    authority: input.authority,\n    generation,\n    runtimeRequestResolutions: new Map(),\n  };\n  registrations.set(input.runId, registeredAuthority);\n  const currentKey = input.issueId && input.agentId\n    ? liveAuthorityKey({\n        companyId: input.companyId,\n        issueId: input.issueId,\n        agentId: input.agentId,\n      })\n    : null;","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/realtime/runner-prp-ws.ts#L113-L149","documentation":"Thrown by registerRunnerPrpAuthority when a runner attempts to register as the live PRP authority for a runId that already has an active registration. Each run may have exactly one live authority at a time; duplicate registration is rejected to prevent two transports steering the same run.","triggerScenarios":"A runner reconnects/retries its websocket and calls registerRunnerPrpAuthority again without the previous registration being torn down; two runner processes claim the same runId.","commonSituations":"Websocket reconnect storm after network blip where server-side cleanup lags; duplicated runner processes after a supervisor restart; run resumed in a second process while the first still holds the registration.","solutions":["Wait for/deregister the existing authority before re-registering (check registrations for the runId first)","Ensure the old runner process is terminated or its registration released on disconnect","Use a single runner process per runId; guard against supervisor double-start","Retry registration with backoff until the stale registration is cleaned up"],"exampleFix":"// before\nregisterRunnerPrpAuthority({ runId, companyId }); // throws if already registered\n// after\ntry {\n  registerRunnerPrpAuthority({ runId, companyId });\n} catch (e) {\n  if (e.message === 'runner_prp_authority_already_registered') {\n    await waitForAuthorityRelease(runId);\n    registerRunnerPrpAuthority({ runId, companyId });\n  } else throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (registrations.has(runId)) await releaseAuthority(runId); // or wait before registering","typeGuard":"const canRegister = (runId, regs) => !regs.has(runId);","tryCatchPattern":"try { registerRunnerPrpAuthority(input) } catch (e) { if (e.message === 'runner_prp_authority_already_registered') { await backoffRetry(register, input); } else throw e; }","preventionTips":["Run exactly one runner process per runId","Release authority registration on runner shutdown (SIGTERM handlers)","Use jittered backoff on websocket reconnect before re-registering","Guard supervisors against double-starting runners for the same run"],"tags":["websocket","registration","conflict"],"backgroundTag":"address-already-in-use","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}