{"record":{"id":"a2ba70b5bc95b8a5","repo":"different-ai/openwork","slug":"agent-diagnostics-in-progress","errorCode":"agent_diagnostics_in_progress","errorMessage":"Agent diagnostics are already in progress","messagePattern":"Agent diagnostics are already in progress","errorType":"http","errorClass":"ApiError","httpStatus":429,"severity":"warning","filePath":"apps/server/src/server.ts","lineNumber":214,"sourceCode":"    const oldest = agentDiagnosticsLastRun.keys().next().value;\n    if (oldest) agentDiagnosticsLastRun.delete(oldest);\n  }\n  agentDiagnosticsLastRun.set(key, now);\n}\n\nfunction reserveAgentDiagnosticsRun(\n  config: ServerConfig,\n  actor: Actor | undefined,\n  workspaceId: string,\n): () => void {\n  const key = agentDiagnosticsActorWorkspaceKey(actor, workspaceId);\n  const inFlight = agentDiagnosticsInFlightByServer.get(config) ?? new Set<string>();\n  agentDiagnosticsInFlightByServer.set(config, inFlight);\n  // Preserve the existing cooldown response for ordinary repeated attempts.\n  // A zero/expired cooldown still cannot bypass the in-flight reservation.\n  requireAgentDiagnosticsRateLimit(config, actor, workspaceId);\n  if (inFlight.has(key)) {\n    throw new ApiError(429, \"agent_diagnostics_in_progress\", \"Agent diagnostics are already in progress\");\n  }\n  if (inFlight.size >= AGENT_DIAGNOSTICS_MAX_IN_FLIGHT_PER_SERVER) {\n    throw new ApiError(429, \"agent_diagnostics_busy\", \"Agent diagnostics are temporarily busy\");\n  }\n\n  // The cooldown charge and reservation are synchronous, so no second request\n  // for this actor/workspace can slip in between them.\n  inFlight.add(key);\n  let released = false;\n  return () => {\n    if (released) return;\n    released = true;\n    inFlight.delete(key);\n  };\n}\n\nconst OPENWORK_VOICE_REALTIME_TOOLS = [\n  {","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/server.ts#L196-L232","documentation":"This 429 error is thrown by reserveAgentDiagnosticsRun when the same actor/workspace key already has an in-flight agent diagnostics run registered on the server. The reservation set (agentDiagnosticsInFlightByServer) tracks active runs per server config; a second request with the same key is rejected rather than queued. It protects the engine from concurrent duplicate diagnostics that would waste resources or corrupt state.","triggerScenarios":"POSTing an agent diagnostics request for the same server+actor+workspace while a previous diagnostics run for that exact key is still active (inFlight.has(key) is true). Happens when clients retry without waiting for the first run to finish, or fire parallel identical requests.","commonSituations":"Double-clicking a 'Run diagnostics' button; a client retrying after a slow response; a scheduled job overlapping a manually triggered run; UI not disabling the trigger while diagnostics run.","solutions":["Wait for the in-flight run to complete before retrying","Check the current run's status via the diagnostics status endpoint instead of re-issuing","Add client-side debounce/lock so only one diagnostics request is outstanding per workspace","Poll with backoff rather than immediate retries on 429"],"exampleFix":"// before\nawait Promise.all([runDiagnostics(serverId), runDiagnostics(serverId)]);\n// after\nconst existing = inFlightRuns.get(serverId);\nif (!existing) inFlightRuns.set(serverId, runDiagnostics(serverId));\nawait inFlightRuns.get(serverId);","handlingStrategy":"retry","validationCode":"// track in-flight runs client-side\nif (activeRuns.has(serverKey)) throw new Error(\"diagnostics already running for this workspace\");","typeGuard":null,"tryCatchPattern":"try {\n  await reserveAgentDiagnosticsRun(config);\n} catch (e) {\n  if (e.code === \"agent_diagnostics_in_progress\") {\n    await waitForExistingRun(key); // poll status instead of retrying\n  } else throw e;\n}","preventionTips":["Disable the diagnostics UI trigger while a run is active","Track outstanding requests per workspace in a Set/Map","Use polling of run status instead of duplicate submissions"],"tags":["rate-limit","concurrency","diagnostics"],"backgroundTag":"resource-already-in-progress","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}