{"record":{"id":"1a3fdc9bd6936daf","repo":"danielmiessler/Fabric","slug":"errordata-error-http-error-status-response","errorCode":null,"errorMessage":"errorData.error || `HTTP error! status: ${response.status}`","messagePattern":"errorData\\.error \\|\\| `HTTP error! status: (.+?)`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/lib/services/transcriptService.ts","lineNumber":48,"sourceCode":"        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        url,\n        language: originalLanguage // Pass original language to server\n      })\n    });\n\n    console.log('2. Server response:', {\n      status: response.status,\n      ok: response.ok,\n      type: response.type,\n      originalLanguage,\n      currentLanguage: get(languageStore)\n    });\n\n    if (!response.ok) {\n      const errorData = await response.json();\n      throw new Error(errorData.error || `HTTP error! status: ${response.status}`);\n    }\n\n    const data = await response.json();\n    if (data.error) {\n      throw new Error(data.error);\n    }\n\n    // Decode HTML entities in transcript\n    data.transcript = decodeHtmlEntities(data.transcript);\n\n    // Ensure language is preserved\n    if (get(languageStore) !== originalLanguage) {\n      console.log('3a. Restoring original language:', originalLanguage);\n      languageStore.set(originalLanguage);\n    }\n\n    console.log('3b. Processed transcript:', {\n      status: response.status,","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/services/transcriptService.ts#L30-L66","documentation":"transcriptService throws the server's errorData.error (or the generic HTTP status fallback) when its fetch responds non-OK. The endpoint returned JSON with an error field, which is relayed verbatim; the fallback fires when the body is not JSON or lacks error.","triggerScenarios":"Requesting a transcript for a video whose language/translation the server cannot fetch; missing subtitles for the requested language; invalid video URL; downstream YouTube-dl service failing so the handler answers 4xx/5xx with an error body.","commonSituations":"Video has no captions in the chosen language; transcript service rate-limited or blocked; malformed video ID; languageStore changed mid-request causing a language mismatch server-side.","solutions":["Read errorData.error — it names the exact server-side cause (no captions, fetch failure, bad URL)","Verify the video actually has subtitles in the requested language","If response.json() itself throws, handle non-JSON error bodies by falling back to response.text()"],"exampleFix":"// before\nif (!response.ok) {\n  const errorData = await response.json();\n  throw new Error(errorData.error || `HTTP error! status: ${response.status}`);\n}\n\n// after\nif (!response.ok) {\n  const text = await response.text();\n  let msg = `HTTP error! status: ${response.status}`;\n  try { msg = JSON.parse(text).error || msg; } catch { if (text) msg = text; }\n  throw new Error(msg);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isTranscriptHttpError(e: unknown): boolean {\n  return e instanceof Error && /HTTP error! status/.test(e.message);\n}","tryCatchPattern":"try { transcript = await transcriptService.get(videoUrl); }\ncatch (e) {\n  if (isTranscriptHttpError(e) || (e instanceof Error && /caption|subtitle/i.test(e.message))) {\n    disableTranscriptFeature(videoUrl); // expected for caption-less videos\n  } else throw e;\n}","preventionTips":["Handle non-JSON error bodies (response.text() fallback) so parsing never masks the status","Treat caption-unavailable errors as expected, not exceptional"],"tags":["transcript","http","api-client"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}