{"record":{"id":"f706b8908f0adc59","repo":"koala73/worldmonitor","slug":"http-response-status-rpc-tools","errorCode":null,"errorMessage":"HTTP ${response.status}","messagePattern":"HTTP \\$\\{response\\.status\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/mcp/registry/rpc-tools.ts","lineNumber":2480,"sourceCode":"      }\n      const bbox = COUNTRY_BBOXES[code];\n      if (!bbox) return { error: `No airspace coverage for ${code}: that country has no bounding box in the dataset.` };\n      const box = countryBox(code);\n      const queryBoxes = box ? splitCountryBox(box) : [];\n      if (!queryBoxes.length) return { error: `No airspace coverage for ${code}: its full-longitude extent cannot scope a country flight query.` };\n      const [sw_lat, sw_lon, ne_lat, ne_lon] = bbox;\n      const type = String(params.type ?? 'all');\n      const UA = 'worldmonitor-mcp-edge/1.0';\n      const queries = queryBoxes.map(bounds =>\n        `sw_lat=${bounds.south}&sw_lon=${bounds.west}&ne_lat=${bounds.north}&ne_lon=${bounds.east}`);\n\n      async function fetchParts<T>(urls: string[], operation: string): Promise<(T | null)[]> {\n        const parts = await Promise.allSettled(urls.map(async url => {\n          const auth = await buildAuthHeaders(context, 'GET', url, null);\n          if (!auth) return null;\n          const response = await fetch(url, { headers: { ...auth, 'User-Agent': UA }, signal: AbortSignal.timeout(8_000) });\n          throwIfBillingDenial(response, operation);\n          if (!response.ok) throw new Error(`HTTP ${response.status}`);\n          return response.json() as Promise<T>;\n        }));\n        // A failure in one half must not hide a billing denial in the other.\n        for (const part of parts) {\n          if (part.status === 'rejected' && part.reason instanceof BillingDenialError) throw part.reason;\n        }\n        return parts.map(part => {\n          if (part.status === 'rejected') throw part.reason;\n          return part.value;\n        });\n      }\n\n      const [civResult, milResult] = await Promise.allSettled([\n        type === 'military' ? Promise.resolve(null) : fetchParts<TrackAircraftResponse>(\n          queries.map(query => `${base}/api/aviation/v1/track-aircraft?${query}`), 'get-airspace-civilian'),\n        type === 'civilian' ? Promise.resolve(null) : fetchParts<ListMilitaryFlightsResponse>(\n          queries.map(query => `${base}/api/military/v1/list-military-flights?${query}&page_size=100`), 'get-airspace-military'),\n      ]);","sourceCodeStart":2462,"sourceCodeEnd":2498,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/api/mcp/registry/rpc-tools.ts#L2462-L2498","documentation":"fetchParts fetches multiple upstream URLs in parallel and throws a generic Error(`HTTP ${status}`) when any part returns a non-ok response (after billing denials are handled separately). The message is intentionally terse; the actual status code is embedded in the message and the specific upstream body is not surfaced.","triggerScenarios":"Any RPC registry tool that fans out to multiple upstream endpoints via fetchParts where one endpoint returns 404/500/502/503, or an auth-less URL (buildAuthHeaders returning null yields null parts, but a bad-token call yields 401). Timeouts are separately handled by AbortSignal.timeout(8000).","commonSituations":"Upstream endpoint path changed or removed (404); upstream service degraded (5xx); expired credentials returning 401; calling a URL built from stale config.","solutions":["Read the thrown message's status code and check the corresponding upstream endpoint's health/logs","Fix the URL/path or credentials that produce the non-2xx status","Add retry-with-backoff for transient 5xx statuses","Consider enriching the error with the URL/status context at the call site to ease diagnosis"],"exampleFix":"// before\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\n// after\nif (!response.ok) throw new Error(`HTTP ${response.status} from ${url}: ${await response.text().catch(() => '')}`);","handlingStrategy":"retry","validationCode":"// pre-flight reachability\nconst probe = await fetch(url, { method: 'HEAD' }); if (!probe.ok) throw new Error(`upstream ${url} unhealthy: ${probe.status}`);","typeGuard":"null","tryCatchPattern":"try { return await fetchParts(urls, op); } catch (e) { if (/^HTTP 5\\d\\d$/.test(e.message)) return retryWithBackoff(() => fetchParts(urls, op), 3); throw e; }","preventionTips":["Include the URL and status in thrown errors for diagnosability","Monitor upstream endpoint health and pin to versioned endpoint paths","Retry only transient statuses (429, 5xx), never 4xx validation failures","Set alerts on upstream 5xx rates"],"tags":["http","upstream","fetch","network"],"backgroundTag":"http-error-response","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}