gastownhall/beads · error

legacy SQLite ephemeral comment text is %d bytes (current TE

Error message

legacy SQLite ephemeral comment text is %d bytes (current TEXT maximum %d)

What it means

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.

Source

Thrown at internal/migration/legacysqlite/reader.go:968

		if err := checkUTF8(
			currentString{"comment issue_id", issueID},
			currentString{"comment author", author},
			currentString{"comment text", text},
		); err != nil {
			return err
		}
		if err := checkCurrentVarchars(
			currentVarchar{"comment issue_id", issueID, types.MaxFieldLen},
			currentVarchar{"comment author", author, types.MaxFieldLen},
		); err != nil {
			return err
		}
		issue := byID[issueID]
		if issue == nil {
			return fmt.Errorf("orphan comment for %s", issueID)
		}
		if issue.Ephemeral && len(text) > currentTextBytes {
			return fmt.Errorf("legacy SQLite ephemeral comment text is %d bytes (current TEXT maximum %d)", len(text), currentTextBytes)
		}
		created, e := parseTime(at)
		if e != nil {
			return e
		}
		if created.IsZero() {
			return fmt.Errorf("comment created_at is zero for issue %s", issueID)
		}
		identity := commentIdentity{issueID: issueID, author: author, text: text, createdAt: created}
		if priorID, exists := seenComments[identity]; exists {
			return fmt.Errorf("legacy SQLite comments %d and %d share current import identity", priorID, id)
		}
		seenComments[identity] = id
		issue.Comments = append(issue.Comments, &types.Comment{ID: strconv.FormatInt(id, 10), IssueID: issueID, Author: author, Text: text, CreatedAt: created})
	}
	return comments.Err()
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Trim or split the oversized comment text in the legacy DB so it fits within the current byte maximum
  2. Reclassify the parent issue as non-ephemeral in the legacy DB if the large comment is essential
  3. Archive the full text outside bd and insert a shortened placeholder comment before migrating

Example fix

-- before
-- comment text length 12000 bytes > ephemeral max 8000
UPDATE comments SET text = substr(text, 1, 8000)
WHERE length(cast(text as blob)) > 8000
  AND issue_id IN (SELECT id FROM issues WHERE ephemeral = 1);
-- after: comment fits the ephemeral TEXT maximum
Defensive patterns

Strategy: validation

Validate before calling

const MAX = currentTextBytes;
for (const c of legacyComments.filter(c => ephemeralIssueIds.has(c.issue_id))) {
  if (Buffer.byteLength(c.text, 'utf8') > MAX)
    throw new Error(`ephemeral comment too large on ${c.issue_id}: ${Buffer.byteLength(c.text)} > ${MAX}`);
}

Type guard

function fitsEphemeralLimit(c) {
  return !ephemeralIssueIds.has(c.issue_id) || Buffer.byteLength(c.text, 'utf8') <= currentTextBytes;
}

Try / catch

try { migrateLegacySQLite(dbPath) } catch (e) {
  if (e.message.includes('ephemeral comment text is')) {
    truncateOversizedEphemeralComments(dbPath);
    retry();
  } else throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/ceecf05d21ec09b1. Report an issue: GitHub.