{"record":{"id":"2b3cdfdb94fe4bd0","repo":"paperclipai/paperclip","slug":"paperclip-service-did-not-become-healthy-expected","errorCode":null,"errorMessage":"Paperclip service did not become healthy${expectedVersion ? ` at version ${expectedVersion}` : \"\"}: ${last.error ?? `reported ${last.serverVersion ?? \"no version\"}`}","messagePattern":"Paperclip service did not become healthy(.+?)` : \"\"\\}: (.+?)`\\}","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/commands/service.ts","lineNumber":50,"sourceCode":"async function probeHealth(instanceId: string): Promise<HealthResult> {\n  try {\n    const response = await fetch(healthUrl(instanceId), { signal: AbortSignal.timeout(2_000) });\n    const body = await response.json() as { status?: unknown; serverVersion?: unknown; version?: unknown };\n    return { ok: response.ok && body.status === \"ok\", serverVersion: typeof body.serverVersion === \"string\" ? body.serverVersion : typeof body.version === \"string\" ? body.version : null };\n  } catch (error) {\n    return { ok: false, serverVersion: null, error: error instanceof Error ? error.message : String(error) };\n  }\n}\n\nasync function waitForHealth(instanceId: string, expectedVersion: string | null, timeoutMs = 60_000): Promise<HealthResult> {\n  const deadline = Date.now() + timeoutMs;\n  let last: HealthResult = { ok: false, serverVersion: null };\n  while (Date.now() < deadline) {\n    last = await probeHealth(instanceId);\n    if (last.ok && (!expectedVersion || last.serverVersion === expectedVersion)) return last;\n    await new Promise((resolve) => setTimeout(resolve, 500));\n  }\n  throw new Error(`Paperclip service did not become healthy${expectedVersion ? ` at version ${expectedVersion}` : \"\"}: ${last.error ?? `reported ${last.serverVersion ?? \"no version\"}`}`);\n}\n\nexport function resolveRestartExpectedVersion(expectedVersion: string | null | undefined): string | null {\n  return expectedVersion ?? null;\n}\n\nexport async function withHotRestartLock<T>(\n  instanceId: string,\n  callback: () => Promise<T>,\n  options: { timeoutMs?: number; pollMs?: number; isProcessAlive?: (pid: number) => boolean } = {},\n): Promise<T> {\n  const instanceRoot = resolvePaperclipInstanceRoot(instanceId);\n  const lockPath = path.join(instanceRoot, \"hot-restart.lock\");\n  const token = `${process.pid}:${Date.now()}:${Math.random().toString(16).slice(2)}`;\n  const deadline = Date.now() + (options.timeoutMs ?? 120_000);\n  const pollMs = options.pollMs ?? 100;\n  const isProcessAlive = options.isProcessAlive ?? ((pid: number) => {\n    try {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/cli/src/commands/service.ts#L32-L68","documentation":"Error \"Paperclip service did not become healthy${expectedVersion ? ` at version ${expectedVersion}` : \"\"}: ${last.error ?? `reported ${last.serverVersion ?? \"no version\"}`}\" thrown in paperclipai/paperclip.","triggerScenarios":"Thrown at cli/src/commands/service.ts:50 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Check service logs for the startup failure, fix the cause, and restart the service."],"exampleFix":null,"handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}