{"record":{"id":"295d7b97b21a7ae3","repo":"gastownhall/beads","slug":"get-issue-labels-w","errorCode":null,"errorMessage":"get issue labels: %w","messagePattern":"get issue labels: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/get_issue.go","lineNumber":61,"sourceCode":"\treturn optionalBlockedTable(issueTable) && dberrors.IsMissingTable(err, issueTable)\n}\n\nfunc getIssueFromTableInTx(ctx context.Context, tx DBTX, issueTable, labelTable, id string) (*types.Issue, error) {\n\t//nolint:gosec // G201: issueTable is a hardcoded literal supplied by GetIssueInTx (\"issues\" or \"wisps\")\n\trow := tx.QueryRowContext(ctx, fmt.Sprintf(`SELECT %s FROM %s %s WHERE id = ?`,\n\t\tIssueSelectColumns, issueTable, sqlbuild.LeaseJoin(issueTable)), id)\n\tissue, err := ScanIssueFrom(row)\n\tif err == sql.ErrNoRows || missingOptionalIssueTable(err, issueTable) {\n\t\treturn nil, storage.ErrNotFound\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get issue: %w\", err)\n\t}\n\n\t// Fetch labels in the same transaction to avoid MaxOpenConns=1 deadlock.\n\tlabels, err := GetLabelsInTx(ctx, tx, labelTable, id)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"get issue labels: %w\", err)\n\t}\n\tissue.Labels = labels\n\n\treturn issue, nil\n}\n","sourceCodeStart":43,"sourceCodeEnd":67,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/get_issue.go#L43-L67","documentation":"This error wraps a failure from GetLabelsInTx while loading an issue's labels inside the same transaction used to fetch the issue row. The issue row itself was read successfully, but the subsequent label lookup against the label table failed, so the whole getIssueFromTableInTx call aborts with no partial data returned. It exists to preserve context ('which step of issue load failed') while retaining the underlying driver error via %w.","triggerScenarios":"Calling GetIssueInTx or getJournalIssueInTx when the labels table is missing/corrupted, the transaction has been invalidated by a prior error or context cancellation, the underlying SQL query in GetLabelsInTx fails (syntax/lock timeout/connection drop), or the tx handle is dead due to the MaxOpenConns=1 pool being starved.","commonSituations":"Schema drift after upgrading beads where label tables weren't migrated; database locked by another long-running transaction (common with Dolt/SQLite embedded mode); context deadline exceeded during large batch reads; corrupted database file.","solutions":["Check the wrapped cause (errors.Unwrap / %v chain) to see the real driver error from GetLabelsInTx","Verify the label table exists and matches the current schema (run bd migration/doctor checks)","Check for connection pool starvation: ensure the same tx is used for labels (it already is) and no external long transaction holds locks","Retry the operation; if transient lock timeouts persist, check for other processes holding the DB"],"exampleFix":"// before\nlabels, err := GetLabelsInTx(ctx, tx, labelTable, id)\nif err != nil {\n\treturn nil, fmt.Errorf(\"get issue labels: %w\", err)\n}\n// after\nlabels, err := GetLabelsInTx(ctx, tx, labelTable, id)\nif err != nil {\n\treturn nil, fmt.Errorf(\"get issue labels for %s: %w\", id, err) // include issue id for debugging\n}","handlingStrategy":"try-catch","validationCode":"// before calling GetIssueInTx, verify DB reachability and schema\nif err := db.PingContext(ctx); err != nil {\n\treturn fmt.Errorf(\"database unreachable: %w\", err)\n}\nvar n int\nif err := db.QueryRowContext(ctx, `SELECT COUNT(*) FROM issue_labels LIMIT 1`).Scan(&n); err != nil {\n\treturn fmt.Errorf(\"label table missing or unreadable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"issue, err := GetIssueInTx(ctx, tx, id)\nif err != nil {\n\tif errors.Is(err, context.DeadlineExceeded) {\n\t\t// retry with fresh context / longer timeout\n\t}\n\tvar derr *driver.Error\n\tif errors.As(err, &derr) {\n\t\tlog.Printf(\"label fetch driver error: %v\", derr)\n\t}\n\treturn fmt.Errorf(\"load issue %s: %w\", id, err)\n}","preventionTips":["Keep all reads for one issue on the same transaction (the code already does this to avoid MaxOpenConns=1 deadlocks)","Run schema migrations before upgrades so label tables match code expectations","Set sane context timeouts for batch reads","Avoid long-running external transactions that hold locks on the labels table"],"tags":["database","labels","transaction","sql"],"backgroundTag":"label-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}