{"record":{"id":"6d038ddd36d889ab","repo":"danielmiessler/Fabric","slug":"data-error","errorCode":null,"errorMessage":"data.error","messagePattern":"data\\.error","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/lib/services/transcriptService.ts","lineNumber":53,"sourceCode":"      })\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,\n      transcriptLength: data.transcript.length,\n      firstChars: data.transcript.substring(0, 100),\n      hasError: !!data.error,\n      videoId: data.title,\n      originalLanguage,","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/danielmiessler/Fabric/blob/338b89cfe97ab2d12ce30ce8b5449857a841366d/web/src/lib/services/transcriptService.ts#L35-L71","documentation":"After a 2xx response, transcriptService checks the parsed body and throws data.error when the server embedded an application-level error in an otherwise successful HTTP reply. This is the envelope-error pattern: transport succeeded, operation failed.","triggerScenarios":"Transcript endpoint returning 200 with { error: 'no captions for language X' } or { error: 'video unavailable' } — operation-level failures the server chose not to signal via status code.","commonSituations":"Backend convention of always-200-with-error-field; partial failures like translation succeeding but transcript retrieval failing; version drift where the frontend expects transcript data but the server emitted an error object.","solutions":["Read the exact data.error string to identify the operation failure","If captions are missing, pick another language or skip transcript features for that video","Prefer fixing the backend to use proper status codes, keeping client checks as defense"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasEnvelopeError(data: unknown): data is { error: string } {\n  return typeof data === 'object' && data !== null && typeof (data as any).error === 'string';\n}","tryCatchPattern":"try { transcript = await transcriptService.get(videoUrl); }\ncatch (e) {\n  if (e instanceof Error && /no captions|unavailable/i.test(e.message)) return null; // soft-fail\n  throw e;\n}","preventionTips":["Guard the parsed body with hasEnvelopeError before using transcript fields","Push the backend toward proper status codes to collapse the two error tiers"],"tags":["transcript","error-envelope","api-client"],"backgroundTag":null,"analyzedSha":"338b89cfe97ab2d12ce30ce8b5449857a841366d","analyzedAt":"2026-08-15T11:38:51.759Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}