{"record":{"id":"ceecf05d21ec09b1","repo":"gastownhall/beads","slug":"legacy-sqlite-ephemeral-comment-text-is-d-bytes","errorCode":null,"errorMessage":"legacy SQLite ephemeral comment text is %d bytes (current TEXT maximum %d)","messagePattern":"legacy SQLite ephemeral comment text is (.+?) bytes \\(current TEXT maximum (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/migration/legacysqlite/reader.go","lineNumber":968,"sourceCode":"\t\tif err := checkUTF8(\n\t\t\tcurrentString{\"comment issue_id\", issueID},\n\t\t\tcurrentString{\"comment author\", author},\n\t\t\tcurrentString{\"comment text\", text},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif err := checkCurrentVarchars(\n\t\t\tcurrentVarchar{\"comment issue_id\", issueID, types.MaxFieldLen},\n\t\t\tcurrentVarchar{\"comment author\", author, types.MaxFieldLen},\n\t\t); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tissue := byID[issueID]\n\t\tif issue == nil {\n\t\t\treturn fmt.Errorf(\"orphan comment for %s\", issueID)\n\t\t}\n\t\tif issue.Ephemeral && len(text) > currentTextBytes {\n\t\t\treturn fmt.Errorf(\"legacy SQLite ephemeral comment text is %d bytes (current TEXT maximum %d)\", len(text), currentTextBytes)\n\t\t}\n\t\tcreated, e := parseTime(at)\n\t\tif e != nil {\n\t\t\treturn e\n\t\t}\n\t\tif created.IsZero() {\n\t\t\treturn fmt.Errorf(\"comment created_at is zero for issue %s\", issueID)\n\t\t}\n\t\tidentity := commentIdentity{issueID: issueID, author: author, text: text, createdAt: created}\n\t\tif priorID, exists := seenComments[identity]; exists {\n\t\t\treturn fmt.Errorf(\"legacy SQLite comments %d and %d share current import identity\", priorID, id)\n\t\t}\n\t\tseenComments[identity] = id\n\t\tissue.Comments = append(issue.Comments, &types.Comment{ID: strconv.FormatInt(id, 10), IssueID: issueID, Author: author, Text: text, CreatedAt: created})\n\t}\n\treturn comments.Err()\n}\n","sourceCodeStart":950,"sourceCodeEnd":986,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/migration/legacysqlite/reader.go#L950-L986","documentation":"When migrating a comment that belongs to an ephemeral (short-lived) issue, the reader enforces the current TEXT byte maximum: if the comment text exceeds currentTextBytes the import aborts, because the current storage cannot hold it.","triggerScenarios":"Legacy SQLite comment rows attached to an issue where issue.Ephemeral is true and len(text) exceeds the current ephemeral TEXT limit in bytes (multi-byte UTF-8 counts per byte, not per rune).","commonSituations":"Long log excerpts or pasted output stored as comments on ephemeral issues in old databases; limits tightened since the legacy DB was written so previously-legal comments now exceed the cap.","solutions":["Trim or split the oversized comment text in the legacy DB so it fits within the current byte maximum","Reclassify the parent issue as non-ephemeral in the legacy DB if the large comment is essential","Archive the full text outside bd and insert a shortened placeholder comment before migrating"],"exampleFix":"-- before\n-- comment text length 12000 bytes > ephemeral max 8000\nUPDATE comments SET text = substr(text, 1, 8000)\nWHERE length(cast(text as blob)) > 8000\n  AND issue_id IN (SELECT id FROM issues WHERE ephemeral = 1);\n-- after: comment fits the ephemeral TEXT maximum","handlingStrategy":"validation","validationCode":"const MAX = currentTextBytes;\nfor (const c of legacyComments.filter(c => ephemeralIssueIds.has(c.issue_id))) {\n  if (Buffer.byteLength(c.text, 'utf8') > MAX)\n    throw new Error(`ephemeral comment too large on ${c.issue_id}: ${Buffer.byteLength(c.text)} > ${MAX}`);\n}","typeGuard":"function fitsEphemeralLimit(c) {\n  return !ephemeralIssueIds.has(c.issue_id) || Buffer.byteLength(c.text, 'utf8') <= currentTextBytes;\n}","tryCatchPattern":"try { migrateLegacySQLite(dbPath) } catch (e) {\n  if (e.message.includes('ephemeral comment text is')) {\n    truncateOversizedEphemeralComments(dbPath);\n    retry();\n  } else throw e;\n}","preventionTips":["Trim or archive oversized comments on ephemeral issues before migrating","Count UTF-8 bytes, not characters, when checking sizes","Re-run the size check after any tooling change that edits comment text"],"tags":["migration","sqlite","size-limit"],"backgroundTag":"text-size-limit-exceeded","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}