{"record":{"id":"8dc56d5b36b76efd","repo":"nexu-io/open-design","slug":"upstream-unavailable","errorCode":"UPSTREAM_UNAVAILABLE","errorMessage":"upstream ${protocol} network error: ${message}","messagePattern":"upstream (.+?) network error: (.+?)","errorType":"http","errorClass":"FinalizeUpstreamError","httpStatus":502,"severity":"error","filePath":"apps/daemon/src/design/finalize-design.ts","lineNumber":396,"sourceCode":"      if (options.apiVersion) callParams.apiVersion = options.apiVersion;\n      callParams.signal = options.signal\n        ? AbortSignal.any([options.signal, timeoutController.signal])\n        : timeoutController.signal;\n      if (options.fetchImpl) callParams.fetchImpl = options.fetchImpl;\n      try {\n        response = await callFinalizeProviderWithRetry(callParams);\n      } catch (err: unknown) {\n        if (err instanceof FinalizeUpstreamError) throw err;\n        const errName =\n          err && typeof err === 'object' && 'name' in err\n            ? (err as { name?: unknown }).name\n            : '';\n        if (errName === 'AbortError') throw err; // route handler maps to 503\n        // Network-level failure (TypeError from fetch, ENOTFOUND/ECONNREFUSED\n        // via cause.code, etc.) — rewrap as upstream failure so the route\n        // handler maps to 502 UPSTREAM_FAILED with redacted details.\n        const message = err instanceof Error ? err.message : String(err);\n        throw new FinalizeUpstreamError(502, '', `upstream ${protocol} network error: ${message}`);\n      }\n    } finally {\n      clearTimeout(timeoutId);\n    }\n\n    // Phase 8: extract DESIGN.md body and usage counters. A 200 with a body\n    // that isn't valid JSON (or isn't an object) is treated as an upstream\n    // failure rather than letting JSON.parse's SyntaxError surface as 500.\n    let payload: unknown;\n    try {\n      payload = await response.json();\n    } catch (err: unknown) {\n      const message = err instanceof Error ? err.message : String(err);\n      throw new FinalizeUpstreamError(\n        502,\n        '',\n        `upstream ${providerLabel(protocol)} returned non-JSON body: ${message}`,\n      );","sourceCodeStart":378,"sourceCodeEnd":414,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/design/finalize-design.ts#L378-L414","documentation":"The fetch to the provider threw an error that was neither a FinalizeUpstreamError nor an AbortError — typically TypeError (invalid URL / network failure), ENOTFOUND (DNS), ECONNREFUSED, ECONNRESET, or a TLS handshake failure. It is rewrapped as FinalizeUpstreamError(502) so the route maps it to 502 UPSTREAM_UNAVAILABLE with redacted details.","triggerScenarios":"DNS resolution failure for the provider baseUrl; connection refused (e.g. Ollama not running, wrong port); connection reset mid-request; TLS/cert error; an invalid baseUrl (missing scheme, typo); offline host.","commonSituations":"Wrong baseUrl (typo, missing https://); Ollama not started locally; the daemon host is offline or behind a blocking corporate proxy; a self-signed cert; the provider endpoint moved; IPv6/IPv4 DNS issues.","solutions":["Verify the baseUrl is reachable from the daemon host: `curl -i <baseUrl>/v1/messages` (or the provider's health path).","For Ollama, ensure the server is running on the expected host/port (`ollama serve`).","Confirm the baseUrl includes the scheme (https:// or http://) and has no trailing path mistakes.","Check DNS, firewall, and proxy configuration on the daemon host."],"exampleFix":"// before: baseUrl 'anthropic.com' (no scheme -> TypeError)\n// after:  baseUrl 'https://api.anthropic.com'","handlingStrategy":"validation","validationCode":"// Verify the provider endpoint is reachable before finalizing.\nasync function endpointReachable(baseUrl: string): Promise<boolean> {\n  try {\n    const res = await fetch(baseUrl, { method: 'HEAD' });\n    return res.status < 500;\n  } catch {\n    return false;\n  }\n}\nif (!(await endpointReachable(baseUrl))) {\n  return res.status(502).json({ error: 'provider endpoint unreachable' });\n}","typeGuard":"import { FinalizeUpstreamError } from './finalize-design.js';\nfunction isUpstreamError(err: unknown): err is FinalizeUpstreamError {\n  return err instanceof FinalizeUpstreamError;\n}","tryCatchPattern":"import { FinalizeUpstreamError } from './finalize-design.js';\ntry {\n  await finalizeDesignPackage(db, projectsRoot, dsRoot, projectId, options);\n} catch (err) {\n  if (err instanceof FinalizeUpstreamError && err.status === 502 && err.rawText === '') {\n    // network-level failure (DNS / connection refused); route maps to 502\n  }\n  throw err;\n}","preventionTips":["Always include the URL scheme (https://) in baseUrl.","For Ollama, confirm `ollama serve` is running on the expected port.","Check DNS/proxy/firewall on the daemon host before finalizing."],"tags":["finalize","network","upstream","provider","dns","connection"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}