{"record":{"id":"d587ca51fee3b11e","repo":"chatboxai/chatbox","slug":"session-attachment-id-not-found","errorCode":null,"errorMessage":"Session attachment ${id} not found","messagePattern":"Session attachment (.+?) not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/session-attachment-rag/db.ts","lineNumber":668,"sourceCode":"  return false\n}\n\nexport async function markSessionAttachmentFailed(id: number, error: string) {\n  const client = getDatabase()\n  const result = await client.execute({\n    sql: 'UPDATE session_attachment SET status = ?, error = ?, processing_started_at = NULL, completed_at = NULL WHERE id = ? AND status != ?',\n    args: ['failed', error, id, 'canceled'],\n  })\n  if ((result.rowsAffected || 0) > 0) {\n    log.debug(`${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [DB] Marked attachment failed: attachmentId=${id}, error=${error}`)\n  }\n}\n\nexport async function retrySessionAttachment(id: number) {\n  const client = getDatabase()\n  const existing = await getSessionAttachment(id)\n  if (!existing) {\n    throw new Error(`Session attachment ${id} not found`)\n  }\n  if (existing.status !== 'failed') {\n    throw new Error('Only failed session attachments can be retried')\n  }\n  await client.execute({\n    sql: 'UPDATE session_attachment SET status = ?, indexing_stage = ?, total_chunks = 0, embedded_chunks = 0, error = NULL, processing_started_at = NULL, completed_at = NULL WHERE id = ?',\n    args: ['pending', 'queued', id],\n  })\n  log.debug(`${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [DB] Reset attachment to pending: attachmentId=${id}`)\n}\n\nexport async function cancelSessionAttachment(id: number) {\n  const client = getDatabase()\n  await client.execute({\n    sql: 'UPDATE session_attachment SET status = ?, error = NULL, processing_started_at = NULL, completed_at = NULL WHERE id = ? AND status IN (?, ?, ?)',\n    args: ['canceled', id, 'pending', 'indexing', 'failed'],\n  })\n  log.debug(`${SESSION_ATTACHMENT_RAG_LOG_PREFIX} [DB] Marked attachment canceled: attachmentId=${id}`)","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/main/session-attachment-rag/db.ts#L650-L686","documentation":"Thrown by retrySessionAttachment when getSessionAttachment(id) returns null/undefined — i.e. no row exists for the given id. It is the precondition check before the status and reset logic. The numeric id is interpolated into the message.","triggerScenarios":"Calling retrySessionAttachment with an id that was never inserted, was hard-deleted, or whose id type does not match the column (e.g. passing a string '12' that the SQL layer does not coerce). Also after a DB reset/restore where the attachment row is gone but the UI still holds a stale id.","commonSituations":"Frontend retries an attachment whose row was deleted by cleanup; id passed from a cached list that is out of date; race between delete and retry; wrong id passed across IPC boundaries (string vs number).","solutions":["Validate the id still exists (getSessionAttachment) before showing a retry button, or ignore the retry if the row is gone.","Ensure ids are passed as numbers (the SQL uses ? binding with a numeric id).","If the row was intentionally deleted, surface 'attachment no longer exists' to the user instead of an error.","Refresh the attachment list in the UI after deletes to prevent stale retry attempts."],"exampleFix":"// before\nconst existing = await getSessionAttachment(id)\nif (!existing) throw new Error(`Session attachment ${id} not found`)\n\n// caller\ntry { await retrySessionAttachment(id) } catch (e) {\n  if (/not found/.test((e as Error).message)) { /* remove from UI */ }\n}","handlingStrategy":"validation","validationCode":"const existing = await getSessionAttachment(id)\nif (!existing) { ui.removeAttachment(id); return }","typeGuard":"function isAttachmentNotFound(e: unknown): e is Error { return e instanceof Error && /Session attachment \\d+ not found/.test(e.message) }","tryCatchPattern":"try { await retrySessionAttachment(id) } catch (e) { if (isAttachmentNotFound(e)) { ui.removeAttachment(id); return } throw e }","preventionTips":["Pass ids as numbers (SQL binds numerically).","Refresh the attachment list after deletes.","Hide the retry button when the row no longer exists."],"tags":["session-attachment-rag","database","validation","typescript"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}