{"record":{"id":"ec00e725d3e69367","repo":"chatboxai/chatbox","slug":"attachment-content-not-found-or-empty","errorCode":null,"errorMessage":"Attachment content not found or empty","messagePattern":"Attachment content not found or empty","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/session-attachment-rag/file-loaders.ts","lineNumber":101,"sourceCode":"\n      const message = error instanceof Error ? error.message : String(error)\n      log.warn(\n        `${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [FILE] Retrying embedding batch after transient error (attempt ${attempt}/${EMBEDDING_MAX_RETRIES}): ${message}`\n      )\n      await setTimeout(EMBEDDING_RETRY_DELAY_MS * attempt)\n    }\n  }\n}\n\nasync function processAttachment(attachmentId: number) {\n  const attachment = await ensureAttachmentNotCanceled(attachmentId)\n  log.debug(\n    `${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [FILE] Begin processing attachment: id=${attachment.id}, file=\"${attachment.filename}\", parser=${attachment.parserType ?? 'unknown'}, storageKey=${attachment.attachmentStorageKey}`\n  )\n\n  const content = await getStoreBlob(attachment.attachmentStorageKey)\n  if (!content?.trim()) {\n    throw new Error('Attachment content not found or empty')\n  }\n\n  const chunkingPipeline = selectAttachmentChunkingPipeline(attachment.filename)\n  await updateSessionAttachmentIndexingProgress(attachmentId, {\n    indexingStage: 'chunking',\n    totalChunks: 0,\n    embeddedChunks: 0,\n  })\n  const { parents, children } = await buildAttachmentChunks(content, attachment.filename)\n  if (parents.length === 0 || children.length === 0) {\n    throw new Error('Attachment did not produce any retrievable chunks')\n  }\n  await ensureAttachmentNotCanceled(attachmentId)\n  log.debug(\n    `${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [FILE] Chunking completed: attachmentId=${attachment.id}, pipeline=${chunkingPipeline}, parents=${parents.length}, children=${children.length}`\n  )\n\n  const parentIdMap = await replaceAttachmentParentsAndChunks(","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/session-attachment-rag/file-loaders.ts#L83-L119","documentation":"Thrown by processAttachment when getStoreBlob(attachment.attachmentStorageKey) returns null/undefined or a string that is empty/whitespace-only after trim(). It is the first content sanity check before chunking begins. Storage is addressed by attachmentStorageKey, so a missing key or empty blob both surface here.","triggerScenarios":"attachmentStorageKey points at an object store entry that was deleted/expired; the upload completed but the blob write failed silently; the blob exists but contains only whitespace (e.g. a blank text file); the storage backend returned null for a transient outage.","commonSituations":"Blob retention policy cleaned up the attachment's underlying object; file upload interrupted so the blob row exists but content is empty; encrypted blob could not be decrypted and was stored as ''; storage key mis-formed (wrong prefix/bucket).","solutions":["Verify the blob exists in object storage under attachmentStorageKey before triggering processing.","If the blob is genuinely empty, mark the attachment failed with a user-facing 'file is empty' message rather than retrying.","Re-upload the attachment to regenerate the blob if retention deleted it.","Distinguish null vs whitespace-only to give a sharper error (null = missing key, whitespace = empty file)."],"exampleFix":"// before\nif (!content?.trim()) throw new Error('Attachment content not found or empty')\n\n// after: split the two cases\nif (content == null) throw new Error(`Attachment blob missing for key ${attachment.attachmentStorageKey}`)\nif (!content.trim()) throw new Error('Attachment file is empty')","handlingStrategy":"validation","validationCode":"const blob = await getStoreBlob(attachment.attachmentStorageKey)\nif (blob == null) { await markSessionAttachmentFailed(id, 'blob missing'); return }\nif (!blob.trim()) { await markSessionAttachmentFailed(id, 'file is empty'); return }","typeGuard":"function isAttachmentContentEmpty(e: unknown): e is Error { return e instanceof Error && e.message === 'Attachment content not found or empty' }","tryCatchPattern":"// processAttachment's outer loop already catches and marks the attachment failed; ensure the message is stored on the row for user-facing display.","preventionTips":["Verify blob existence in object storage before queueing processing.","Reject empty files at upload with a clear message.","Distinguish null vs empty for sharper diagnostics."],"tags":["session-attachment-rag","storage","validation","typescript"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}