{"record":{"id":"c2ff16c7dc2ffbcd","repo":"koala73/worldmonitor","slug":"forcereleaselease-no-ramp-configured","errorCode":null,"errorMessage":"[forceReleaseLease] no ramp configured","messagePattern":"\\[forceReleaseLease\\] no ramp configured","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"convex/broadcast/rampRunner.ts","lineNumber":672,"sourceCode":"/**\n * Operator-only last-resort lease release.\n *\n * Use ONLY when a cron action is genuinely wedged (process died silently\n * between claim and any catch block, leaving a held lease with no\n * partial-failure status). Investigate Convex action logs + Resend dashboard\n * BEFORE calling this — the side effects might have actually completed\n * (segment created, broadcast sent) and the right recovery is then\n * `recoverFromPartialFailure({recovery:\"manual-finished\"})`, not a fresh send.\n *\n * Sets `lastRunStatus = \"partial-failure\"` so `recoverFromPartialFailure`\n * picks up; preserves any `pending*` progress markers so the operator can\n * decide between manual-finished and discard-and-rotate from persisted state.\n */\nexport const forceReleaseLease = internalMutation({\n  args: { reason: v.string() },\n  handler: async (ctx, { reason }) => {\n    const row = await loadConfig(ctx);\n    if (!row) throw new Error(\"[forceReleaseLease] no ramp configured\");\n    if (!row.pendingRunId) {\n      return {\n        ok: true as const,\n        noop: true as const,\n        currentStatus: row.lastRunStatus,\n      };\n    }\n    const releasedRunId = row.pendingRunId;\n    const heldForMs =\n      row.pendingRunStartedAt !== undefined\n        ? Date.now() - row.pendingRunStartedAt\n        : undefined;\n    await ctx.db.patch(row._id, {\n      pendingRunId: undefined,\n      pendingRunStartedAt: undefined,\n      lastRunStatus: \"partial-failure\",\n      lastRunAt: Date.now(),\n      lastRunError: `forced-release: ${reason.slice(0, 200)} (was held by ${releasedRunId}${heldForMs !== undefined ? `, age ${Math.round(heldForMs / 1000)}s` : \"\"})`,","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/convex/broadcast/rampRunner.ts#L654-L690","documentation":"Operator guard in the forceReleaseLease internal mutation: loadConfig returned no broadcastRampConfig row, so there is no lease to force-release. The last-resort wedge-recovery tool cannot run because the ramp was never configured on this deployment.","triggerScenarios":"Thrown at convex/broadcast/rampRunner.ts:670 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Run configureRamp before using lease-recovery tooling","Confirm the deployment actually has a ramp — a missing config row usually means wrong environment"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}