gastownhall/beads · error
add label: %w
Error message
add label: %w
What it means
AddLabelInTx returns this when the INSERT IGNORE of a label row into labels/wisp_labels fails at execution time. The library uses INSERT IGNORE so duplicate labels are idempotent; any error here is a real failure (constraint violation other than duplicates, missing table, connection error). An associated derived event and update journal entry are only written after this succeeds.
Source
Thrown at internal/storage/issueops/labels.go:153
// Reject an over-length label up front. The INSERT IGNORE below would
// otherwise silently truncate it to the VARCHAR(255) column, storing a label
// the caller never sent; a typed ErrFieldTooLong is the clean rejection.
if err := types.CheckFieldLen("label", label); err != nil {
return err
}
if labelTable == "" || eventTable == "" {
isWisp := IsActiveWispInTx(ctx, tx, issueID)
_, lt, et, _ := WispTableRouting(isWisp)
if labelTable == "" {
labelTable = lt
}
if eventTable == "" {
eventTable = et
}
}
//nolint:gosec // G201: labelTable is from WispTableRouting ("labels" or "wisp_labels")
if _, err := tx.ExecContext(ctx, fmt.Sprintf(`INSERT IGNORE INTO %s (issue_id, label) VALUES (?, ?)`, labelTable), issueID, label); err != nil {
return fmt.Errorf("add label: %w", err)
}
comment := "Added label: " + label
if err := InsertDerivedEvent(ctx, tx, eventTable, AuxEvent{
IssueID: issueID,
EventType: types.EventLabelAdded,
Actor: actor,
Comment: str(comment),
}); err != nil {
return fmt.Errorf("add label: record event: %w", err)
}
// A label is part of the bead snapshot, so a label write journals as an
// update carrying the complete post-mutation set.
return RecordEventInTx(ctx, tx, EventUpdate, issueID, actor)
}
// RemoveLabelInTx removes a label from an issue and records an event within
// an existing transaction. Automatically routes to wisp tables if the ID is
// an active wisp.View on GitHub (pinned to 71377f2769)
Solutions
- Verify the issue exists before adding the label
- Run schema migrations to ensure label tables exist
- Check the wrapped driver error for FK/constraint messages and correct the input data
Defensive patterns
Strategy: validation
Validate before calling
var n int
if err := tx.QueryRow(`SELECT COUNT(*) FROM issues WHERE id = ?`, issueID).Scan(&n); err != nil || n == 0 {
return fmt.Errorf("issue %s does not exist; cannot add label", issueID)
} Try / catch
if err := issueops.AddLabelInTx(ctx, tx, issueID, label, actor); err != nil {
if strings.Contains(err.Error(), "foreign key") || strings.Contains(err.Error(), "Duplicate") {
// invalid issue or constraint issue: fix input, don't retry blindly
}
return err
} Prevention
- Verify the issue exists before mutating its labels
- Run migrations so labels/wisp_labels tables exist
- Rely on INSERT IGNORE semantics for idempotent duplicate adds — only non-duplicate errors surface
- Check wrapped errors for constraint names to identify data problems
When it happens
Trigger: Calling AddLabelInTx (via ApplyLabelPatch) when the INSERT fails: label table missing, foreign-key violation because the issue doesn't exist, or connection failure within the transaction.
Common situations: Adding a label to an already-deleted issue ID (FK violation); schema version missing wisp_labels; transaction aborted earlier by a prior error leaving the connection in a bad state.
Related errors
- db: CommentSQLRepository.Insert: %w
- get labels from %s: %w
- add label %s/%s: %w
- get issues by IDs: labels from %s: %w
- insert compaction snapshot: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/ad266a113145bf7a.
Report an issue: GitHub.