{"record":{"id":"09aeed05bd0c19db","repo":"angular/angular-cli","slug":"failed-to-fetch-or-parse-content-from-url-e","errorCode":null,"errorMessage":"Failed to fetch or parse content from ${url}: ${e}","messagePattern":"Failed to fetch or parse content from (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/angular/cli/src/commands/mcp/tools/doc-search.ts","lineNumber":227,"sourceCode":"    // Process top hit first\n    const topHit = allHits[0];\n    const { title: topTitle, breadcrumb: topBreadcrumb } = formatHitToParts(topHit);\n    let topContent: string | undefined;\n\n    if (includeTopContent && typeof topHit.url === 'string') {\n      const url = new URL(topHit.url);\n      try {\n        // Only fetch content from angular.dev\n        if (url.hostname === 'angular.dev' || url.hostname.endsWith('.angular.dev')) {\n          const response = await fetch(url);\n          if (response.ok && response.body) {\n            topContent = await extractMainContent(\n              Readable.fromWeb(response.body, { encoding: 'utf-8' }),\n            );\n          }\n        }\n      } catch (e) {\n        logger.warn(`Failed to fetch or parse content from ${url}: ${e}`);\n      }\n    }\n\n    structuredResults.push({\n      title: topTitle,\n      breadcrumb: topBreadcrumb,\n      url: topHit.url as string,\n      content: topContent,\n    });\n\n    let topText = `## ${topTitle}\\n${topBreadcrumb}\\nURL: ${topHit.url}`;\n    if (topContent) {\n      topText += `\\n\\n--- DOCUMENTATION CONTENT ---\\n${topContent}`;\n    }\n    textContent.push({ type: 'text' as const, text: topText });\n\n    // Process remaining hits\n    for (const hit of allHits.slice(1)) {","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/cli/src/commands/mcp/tools/doc-search.ts#L209-L245","documentation":"After finding doc search hits, the tool fetches each URL and extracts main content. Any fetch/HTTP/parse failure for a given URL is caught and logged as this warning; that page's content is simply omitted from structuredResults.","triggerScenarios":"`fetch` of a search-hit URL fails (network error, 404/403/5xx) or the response stream cannot be parsed by extractMainContent (non-HTML, truncated body).","commonSituations":"Stale search index pointing at moved/removed doc pages; rate limiting or 403 from the docs host; transient network drops; redirect loops.","solutions":["Retry the doc search — often transient.","Verify the URL loads in a browser; if 404, the index is stale — update @angular/cli.","Check proxy/firewall rules for angular.dev.","If self-hosting or mirroring docs, fix the content endpoint."],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"const head = await fetch(url, { method: 'HEAD' }).catch(() => null); if (!head || !head.ok) skipUrl(url);","typeGuard":"function hasBody(res: Response): res is Response & { body: ReadableStream } { return res.body !== null; }","tryCatchPattern":"try { const res = await fetch(url); if (!res.ok) throw new Error(String(res.status)); content = await extractMainContent(Readable.fromWeb(res.body, { encoding: 'utf-8' })); } catch (e) { logger.warn(`Failed to fetch or parse content from ${url}: ${e}`); }","preventionTips":["Treat per-URL fetch failures as expected and degrade gracefully.","Verify search-hit URLs resolve (index may be stale).","Keep CLI updated so index URLs are current.","Handle non-HTML responses explicitly."],"tags":["network","fetch","documentation","mcp"],"backgroundTag":"docs-fetch-failed","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}