{"record":{"id":"ecb38fa8703673c7","repo":"gastownhall/beads","slug":"insert-issue-into-s-w","errorCode":null,"errorMessage":"insert issue into %s: %w","messagePattern":"insert issue into (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/helpers.go","lineNumber":157,"sourceCode":"\t\t\t?, ?, ?, ?,\n\t\t\t?, ?, ?,\n\t\t\t?, ?\n\t\t)\n\t\t%s\n\t`, table, suffix),\n\t\tissue.ID, issue.ContentHash, issue.Title, issue.Description, issue.Design, issue.AcceptanceCriteria, issue.Notes,\n\t\tissue.Status, issue.Priority, issue.IssueType, NullString(issue.Assignee), NullInt(issue.EstimatedMinutes),\n\t\tissue.CreatedAt, issue.CreatedBy, issue.Owner, issue.UpdatedAt, issue.StartedAt, issue.ClosedAt, NullStringPtr(issue.ExternalRef), issue.SpecID,\n\t\tissue.CompactionLevel, issue.CompactedAt, NullStringPtr(issue.CompactedAtCommit), NullIntVal(issue.OriginalSize),\n\t\tissue.Sender, issue.Ephemeral, issue.NoHistory, issue.WispType, issue.Pinned, issue.IsTemplate,\n\t\tissue.MolType, issue.WorkType, issue.SourceSystem, issue.SourceRepo, issue.CloseReason, issue.ClosedBySession,\n\t\tissue.EventKind, issue.Actor, issue.Target, issue.Payload,\n\t\tissue.AwaitType, issue.AwaitID, issue.Timeout.Nanoseconds(), FormatJSONStringArray(issue.Waiters),\n\t\tissue.DueAt, issue.DeferUntil, JSONMetadata(issue.Metadata),\n\t\tfreshRowLock(), NullString(string(issue.StorageClass.Normalize())),\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"insert issue into %s: %w\", table, err)\n\t}\n\treturn nil\n}\n\n// RecordEventInTable records an event in the specified events table.\nfunc RecordEventInTable(ctx context.Context, tx DBTX, table, issueID string, eventType types.EventType, actor, newValue string) error {\n\treturn InsertDerivedEvent(ctx, tx, table, AuxEvent{\n\t\tIssueID:   issueID,\n\t\tEventType: eventType,\n\t\tActor:     actor,\n\t\tOldValue:  str(\"\"),\n\t\tNewValue:  str(newValue),\n\t})\n}\n\n// GenerateIssueIDInTable generates a unique ID, checking for collisions\n// in the specified table. Supports counter mode for non-ephemeral issues.\n//","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/helpers.go#L139-L175","documentation":"This error is returned by executeIssueInsert when the raw INSERT of an issue row into the given table fails. It wraps the driver error with the target table name so you know which issue table rejected the insert. Common causes are constraint violations (duplicate primary key, NOT NULL), oversized values, or malformed column data.","triggerScenarios":"Calling insertIssueIntoTable or insertIssueCreateOnly when: the issue ID already exists (duplicate PK), a required column is NULL, the metadata JSON produced by JSONMetadata is invalid for the column type, the row exceeds storage limits, or the table doesn't exist (unmigrated schema).","commonSituations":"Re-creating an issue with a colliding ID after import; writing issues into an old database missing newer columns after a version upgrade; metadata containing characters that break the JSON encoding; disk-full or read-only database in embedded mode.","solutions":["Read the wrapped driver error: 'UNIQUE constraint failed' means duplicate ID — generate a new ID instead of reusing it","Check that the target table exists and has the expected columns (schema migration state)","Validate issue fields before insert: non-empty ID, valid Metadata JSON, sane DueAt/DeferUntil values","If create-only semantics are intended, use insertIssueCreateOnly handling and treat duplicate errors as an 'already exists' outcome"],"exampleFix":"// before\nerr := executeIssueInsert(ctx, tx, table, issue)\nif err != nil {\n\treturn fmt.Errorf(\"insert issue into %s: %w\", table, err)\n}\n// after\nerr := executeIssueInsert(ctx, tx, table, issue)\nif err != nil {\n\tif strings.Contains(err.Error(), \"UNIQUE constraint failed\") {\n\t\treturn ErrIssueExists // map duplicate to a typed sentinel\n\t}\n\treturn fmt.Errorf(\"insert issue into %s: %w\", table, err)\n}","handlingStrategy":"validation","validationCode":"// validate before insert\nif issue.ID == \"\" {\n\treturn errors.New(\"issue ID is empty\")\n}\nvar count int\nif err := tx.QueryRowContext(ctx, `SELECT COUNT(*) FROM issues WHERE id = ?`, issue.ID).Scan(&count); err != nil {\n\treturn err\n}\nif count > 0 {\n\treturn ErrIssueExists\n}\nif _, err := json.Marshal(issue.Metadata); err != nil {\n\treturn fmt.Errorf(\"invalid metadata: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"err := insertIssueIntoTable(ctx, tx, \"issues\", issue)\nif err != nil {\n\tif errors.Is(err, ErrIssueExists) || strings.Contains(err.Error(), \"UNIQUE constraint failed\") {\n\t\t// handle already-exists path (load or skip)\n\t\treturn ErrIssueExists\n\t}\n\treturn err\n}","preventionTips":["Always generate a fresh ID (GenerateIssueIDInTable or counter mode) rather than reusing IDs from imports","Validate Metadata is JSON-serializable before insert","Keep schema migrations in lockstep with code versions","Check available disk space / read-only status for embedded databases"],"tags":["database","insert","sql","constraint-violation"],"backgroundTag":"insert-constraint-violation","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}