{"record":{"id":"95691ef5f696e678","repo":"chatboxai/chatbox","slug":"20029","errorCode":"20029","errorMessage":"local_parser_failed","messagePattern":"local_parser_failed","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/renderer/packages/pdf-parser.ts","lineNumber":38,"sourceCode":"function isPdfTextItem(item: unknown): item is PdfTextItem {\n  return (\n    typeof item === 'object' &&\n    item !== null &&\n    'str' in item &&\n    typeof (item as PdfTextItem).str === 'string' &&\n    Array.isArray((item as PdfTextItem).transform)\n  )\n}\n\nasync function loadPdfjs() {\n  const pdfjs = await import('pdfjs-dist/legacy/build/pdf.mjs')\n  pdfjs.GlobalWorkerOptions.workerSrc = pdfWorkerUrl\n  return pdfjs\n}\n\nexport async function parsePdfFileLocally(file: File): Promise<string> {\n  if (!isPdfFilePath(file.name)) {\n    throw new Error('local_parser_failed')\n  }\n\n  if (file.size > LOCAL_PARSER_MAX_PDF_FILE_SIZE) {\n    throw new Error(LOCAL_PARSER_FILE_TOO_LARGE_ERROR)\n  }\n\n  const { getDocument } = await loadPdfjs()\n  const loadingTask = getDocument({\n    data: new Uint8Array(await file.arrayBuffer()),\n    useSystemFonts: true,\n  })\n\n  try {\n    const document = await loadingTask.promise\n    const pageTexts: string[] = []\n\n    for (let pageNumber = 1; pageNumber <= document.numPages; pageNumber++) {\n      try {","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/renderer/packages/pdf-parser.ts#L20-L56","documentation":"Thrown by parsePdfFileLocally() when isPdfFilePath(file.name) is false — i.e. the file extension is not recognized as PDF. It is an early guard before any pdfjs work is done. The sentinel string 'local_parser_failed' (code 20029) is a stable handle callers match on to route the user toward a server-side/alternative parser.","triggerScenarios":"Calling parsePdfFileLocally() with a File whose name lacks a .pdf extension (or whatever isPdfFilePath accepts). The check `if (!isPdfFilePath(file.name)) throw new Error('local_parser_failed')` fires immediately.","commonSituations":"File picker/attachment pipeline routes a non-PDF file into the PDF parser path; file renamed without .pdf extension but is actually a PDF; a content-type vs filename mismatch where the dispatcher used the wrong parser by extension.","solutions":["Ensure the file genuinely is a PDF and has a .pdf extension before this call.","Route non-PDF files to their correct parser instead of the PDF path.","If the file is a PDF with a missing extension, rename it or fix the upstream dispatcher to use content-type, not extension."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (!isPdfFilePath(file.name)) {\n  // route to the correct parser; do not call parsePdfFileLocally\n}","typeGuard":"function looksLikePdf(file: File): boolean {\n  return file.type === 'application/pdf' || isPdfFilePath(file.name)\n}","tryCatchPattern":"try {\n  await parsePdfFileLocally(file)\n} catch (e) {\n  if (e instanceof Error && e.message === 'local_parser_failed') {\n    // offer alternative parser or reject the attachment\n  }\n}","preventionTips":["Dispatch by content-type AND extension; reject ambiguous files early.","Keep a single source of truth for PDF detection (isPdfFilePath).","Unit-test the dispatcher with renamed and extensionless files."],"tags":["pdf","parser","validation","file-type"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}