{"record":{"id":"d72a0e01f2b1b616","repo":"thedotmack/claude-mem","slug":"classifyclaudeservererror-cause-err","errorCode":null,"errorMessage":"classifyClaudeServerError({ cause: err })","messagePattern":"classifyClaudeServerError\\((.+?)\\)","errorType":"exception","errorClass":"ServerClassifiedProviderError","httpStatus":null,"severity":"error","filePath":"src/server/generation/providers/ClaudeObservationProvider.ts","lineNumber":78,"sourceCode":"    signal?: AbortSignal,\n  ): Promise<ServerGenerationResult> {\n    const { prompt, skippedAll } = buildServerGenerationPrompt(context);\n    if (skippedAll) {\n      // All events were scrubbed by privacy stripping. Don't bill the\n      // provider — return a synthetic skip response that parser accepts.\n      return {\n        rawText: '<skip_summary reason=\"all_events_private\" />',\n        providerLabel: this.providerLabel,\n        modelId: this.model,\n      };\n    }\n\n    let response: Response;\n    try {\n      response = await this.postMessages(prompt, signal);\n    } catch (networkError) {\n      const err = networkError instanceof Error ? networkError : new Error(String(networkError));\n      throw classifyClaudeServerError({\n        cause: err,\n      });\n    }\n\n    if (!response.ok) {\n      const bodyText = await safeReadBody(response);\n      throw classifyClaudeServerError({\n        status: response.status,\n        bodyText,\n        headers: response.headers,\n        cause: new Error(`Anthropic API error: ${response.status} - ${bodyText}`),\n      });\n    }\n\n    let data: AnthropicMessagesResponse;\n    try {\n      data = (await response.json()) as AnthropicMessagesResponse;\n    } catch (parseError) {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/server/generation/providers/ClaudeObservationProvider.ts#L60-L96","documentation":"ClaudeObservationProvider.generate wraps the network call to the Anthropic messages API; any exception from postMessages (fetch rejection) is wrapped via classifyClaudeServerError with only a cause and no HTTP status. This signals a transport-level failure — the request never got an HTTP response. The classified error carries kind information (e.g. retryable vs unrecoverable) derived from the cause.","triggerScenarios":"`postMessages()` rejects: DNS failure, connection refused/reset, TLS error, request timeout, or AbortSignal firing — caught in the try/catch at ClaudeObservationProvider.ts:74-80 and rethrown as classifyClaudeServerError({ cause: err }).","commonSituations":"Missing/blocked network in CI containers, proxy or VPN drops, DNS misconfiguration, ANTHROPIC_BASE_URL pointing at an unreachable host, transient outage of api.anthropic.com.","solutions":["Check network/DNS connectivity to api.anthropic.com from the runtime environment.","Verify the base URL / proxy configuration for the Claude client.","Retry with backoff if the cause is transient (timeout, connection reset).","Inspect the wrapped cause error for the underlying socket/TLS message."],"exampleFix":"// before\nconst res = await provider.generate(prompt, signal);\n// after\ntry { const res = await provider.generate(prompt, signal); }\ncatch (e) { if (e.kind === 'retryable') await sleep(backoff); else throw e; }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isNetworkError(e: unknown): e is TypeError {\n  return e instanceof TypeError && /fetch|network/i.test(e.message);\n}","tryCatchPattern":"try {\n  result = await provider.generate(prompt, signal);\n} catch (e) {\n  if (e.kind === 'retryable') return retryWithBackoff(() => provider.generate(prompt, signal));\n  throw e;\n}","preventionTips":["Check egress/network access to api.anthropic.com in every deployment environment.","Use AbortSignals with sensible timeouts and distinguish abort from network failure.","Always inspect the classified error's `kind` before deciding to retry.","Log the wrapped `cause` — the raw socket/TLS error names the real problem."],"tags":["network","anthropic","fetch","transport-error"],"backgroundTag":"network-request-failed","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}