{"record":{"id":"e0547bcdf2f076b6","repo":"gastownhall/beads","slug":"db-labelsqlrepository-insert-s-s-w","errorCode":null,"errorMessage":"db: LabelSQLRepository.Insert %s/%s: %w","messagePattern":"db: LabelSQLRepository\\.Insert (.+?)/(.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/label.go","lineNumber":56,"sourceCode":"\t}\n\tif label == \"\" {\n\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Insert: label must not be empty\")\n\t}\n\t// Reject an over-length label before the INSERT IGNORE, which would otherwise\n\t// silently truncate it to the VARCHAR(255) column. This is the proxied-server\n\t// (uow) analog of issueops.AddLabelInTx's guard, so both write stacks return a\n\t// typed ErrFieldTooLong instead of storing a label the caller never sent.\n\tif err := types.CheckFieldLen(\"label\", label); err != nil {\n\t\treturn err\n\t}\n\ttable := pickLabelTable(opts.UseWispsTable)\n\t//nolint:gosec // G201: table is one of two hardcoded constants\n\tresult, err := r.runner.ExecContext(ctx,\n\t\tfmt.Sprintf(\"INSERT IGNORE INTO %s (issue_id, label) VALUES (?, ?)\", table),\n\t\tissueID, label,\n\t)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Insert %s/%s: %w\", issueID, label, err)\n\t}\n\trows, err := result.RowsAffected()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Insert %s/%s: rows affected: %w\", issueID, label, err)\n\t}\n\tif rows == 0 {\n\t\tissueTable := \"issues\"\n\t\tif opts.UseWispsTable {\n\t\t\tissueTable = \"wisps\"\n\t\t}\n\t\tvar count int\n\t\t//nolint:gosec // G201: issueTable is one of two hardcoded constants.\n\t\tif err := r.runner.QueryRowContext(ctx, fmt.Sprintf(\"SELECT COUNT(*) FROM %s WHERE id = ?\", issueTable), issueID).Scan(&count); err != nil {\n\t\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Insert %s/%s: verify issue: %w\", issueID, label, err)\n\t\t}\n\t\tif count == 0 {\n\t\t\treturn fmt.Errorf(\"db: LabelSQLRepository.Insert %s/%s: issue does not exist\", issueID, label)\n\t\t}","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/label.go#L38-L74","documentation":"This error wraps any failure from the INSERT IGNORE statement in LabelSQLRepository.Insert, adding the issue ID and label for context. It is thrown when the underlying Dolt/SQL driver rejects the insert (connection problems, schema errors, constraint failures). The %w keeps the driver error chain intact for errors.Is/As checks.","triggerScenarios":"Calling LabelSQLRepository.Insert with a closed/failed DB connection, a malformed label exceeding column length, or a missing/locked `issue_labels` (or `wisp_labels`) table.","commonSituations":"Database not migrated to current schema version; connection dropped mid-request; attempting to insert into the wisps table path when UseWispsTable is set but the table does not exist.","solutions":["Check the wrapped driver error with errors.As to see the root SQL error","Verify the labels table exists via `bd doctor` or a fresh migration","Confirm DB connectivity and that the connection is not closed","Re-check label string for invalid characters or oversized length"],"exampleFix":"// before\nerr := repo.Insert(ctx, issueID, label, opts)\n// after\nif err := repo.Insert(ctx, issueID, label, opts); err != nil {\n    var drv *mysql.MySQLError\n    if errors.As(err, &drv) {\n        log.Errorf(\"label insert driver error %d: %v\", drv.Number, drv)\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"if issueID == \"\" || label == \"\" { return fmt.Errorf(\"issueID and label required\") }\nif err := db.PingContext(ctx); err != nil { return fmt.Errorf(\"db unavailable: %w\", err) }","typeGuard":"func isSQLErr(err error) bool { var e *mysql.MySQLError; return errors.As(err, &e) }","tryCatchPattern":"if err := repo.Insert(ctx, issueID, label, opts); err != nil {\n    var sqle *mysql.MySQLError\n    if errors.As(err, &sqle) { log.Errorf(\"insert failed: %d %s\", sqle.Number, sqle.Message) }\n    return fmt.Errorf(\"add label %q to %s: %w\", label, issueID, err)\n}","preventionTips":["Ping the DB (or check health) before repository calls","Run migrations so the labels table exists","Validate issueID/label inputs at the boundary","Use errors.As to surface the driver-level cause"],"tags":["database","sql","repository","error-wrapping"],"backgroundTag":"sql-insert-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}