{"record":{"id":"c9ecc0d42b3823c2","repo":"gastownhall/beads","slug":"check-remaining-blockers-from-s-w","errorCode":null,"errorMessage":"check remaining blockers from %s: %w","messagePattern":"check remaining blockers from (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependency_queries.go","lineNumber":850,"sourceCode":"\t\tif end > len(candidateIDs) {\n\t\t\tend = len(candidateIDs)\n\t\t}\n\t\tbatch := candidateIDs[start:end]\n\t\tplaceholders, batchArgs := buildSQLInClause(batch)\n\n\t\tremainingByCandidate := make(map[string][]string, len(batch))\n\t\tremainingBlockerSet := make(map[string]struct{})\n\t\tfor _, depTable := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\t\t//nolint:gosec // G201: depTable is hardcoded.\n\t\t\tdepRows, err := tx.QueryContext(ctx, fmt.Sprintf(`\n\t\t\t\tSELECT issue_id, %s AS depends_on_id FROM %s\n\t\t\t\tWHERE issue_id IN (%s) AND type = 'blocks' AND %s != ?\n\t\t\t`, DepTargetExpr, depTable, placeholders, DepTargetExpr), append(batchArgs, closedIssueID)...)\n\t\t\tif err != nil {\n\t\t\t\tif optionalBlockedTable(depTable) && isTableNotExistError(err) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\treturn nil, fmt.Errorf(\"check remaining blockers from %s: %w\", depTable, err)\n\t\t\t}\n\t\t\tfor depRows.Next() {\n\t\t\t\tvar candidateID, blockerID string\n\t\t\t\tif err := depRows.Scan(&candidateID, &blockerID); err != nil {\n\t\t\t\t\t_ = depRows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"scan remaining blocker: %w\", err)\n\t\t\t\t}\n\t\t\t\tremainingByCandidate[candidateID] = append(remainingByCandidate[candidateID], blockerID)\n\t\t\t\tremainingBlockerSet[blockerID] = struct{}{}\n\t\t\t}\n\t\t\t_ = depRows.Close()\n\t\t\tif err := depRows.Err(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"remaining blocker rows from %s: %w\", depTable, err)\n\t\t\t}\n\t\t}\n\n\t\tremainingBlockerIDs := make([]string, 0, len(remainingBlockerSet))\n\t\tfor blockerID := range remainingBlockerSet {","sourceCodeStart":832,"sourceCodeEnd":868,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependency_queries.go#L832-L868","documentation":"Wraps a SQL failure from querying a dependency table for remaining 'blocks' edges while computing newly-unblocked issues inside GetNewlyUnblockedByCloseInTx. The table name is embedded in the message so you know which dependency table (deps or deps_v2 style optional table) failed. It is thrown whenever tx.QueryContext returns an error that is not an ignorable missing-optional-table error, aborting the unblock computation and the surrounding transaction.","triggerScenarios":"Calling GetNewlyUnblockedByCloseInTx after closing an issue when the SQL SELECT against one of the dependency tables fails: malformed schema, corrupted table, lock timeout, or driver-level query error other than table-not-exist on an optional table.","commonSituations":"Partial or failed migrations leaving a dependency table in a bad state; database file corruption in embedded Dolt/SQLite deployments; concurrent DDL during the transaction; permission errors on the dep table.","solutions":["Check the wrapped underlying error (%w) to identify the driver error code","Verify the dependency table schema matches what this version of beads expects (run migrations/bd migrate)","If the table is optional, confirm isTableNotExistError matched; if not, the table exists but is broken — inspect/repair it","Retry the operation after resolving any transient lock or connection issue"],"exampleFix":"// before\nrows, err := tx.QueryContext(ctx, q, args...)\nif err != nil { return nil, err } // loses table context\n// after\nif err != nil {\n\tif optionalBlockedTable(depTable) && isTableNotExistError(err) { continue }\n\treturn nil, fmt.Errorf(\"check remaining blockers from %s: %w\", depTable, err)\n}","handlingStrategy":"try-catch","validationCode":"// before calling close/unblock flows\nif err := bd.Doctor(ctx); err != nil { /* fix schema/storage first */ }\n_ = db.QueryRow(\"SELECT COUNT(*) FROM deps\").Scan(&n) // table must be queryable","typeGuard":null,"tryCatchPattern":"err := tx.CloseIssue(ctx, id)\nif err != nil {\n\tvar wrapped interface{ Unwrap() error }\n\tif errors.Is(err, context.DeadlineExceeded) { /* retry */ }\n\tlog.Fatalf(\"unblock check failed: %v\", err)\n}","preventionTips":["Keep beads upgraded so migrations run before queries","Run `bd doctor` after version upgrades to validate storage schema","Avoid concurrent DDL while bd commands are running","Back up the database before manual schema edits"],"tags":["go","sql","storage","dependencies"],"backgroundTag":"sql-query-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}