{"record":{"id":"28b7096710e7b43a","repo":"gastownhall/beads","slug":"get-dependency-counts-scan-blocker-w","errorCode":null,"errorMessage":"get dependency counts: scan blocker: %w","messagePattern":"get dependency counts: scan blocker: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/dependency_queries.go","lineNumber":481,"sourceCode":"\t\t\t//nolint:gosec // G201: depTable is hardcoded and inClause contains only ? placeholders.\n\t\t\tdepRows, err := tx.QueryContext(ctx, fmt.Sprintf(`\n\t\t\t\tSELECT issue_id, COUNT(*) as cnt\n\t\t\t\tFROM %s\n\t\t\t\tWHERE issue_id IN (%s) AND type = 'blocks'\n\t\t\t\tGROUP BY issue_id\n\t\t\t`, depTable, inClause), args...)\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(\"get dependency counts (blockers from %s): %w\", depTable, err)\n\t\t\t}\n\t\t\tfor depRows.Next() {\n\t\t\t\tvar id string\n\t\t\t\tvar cnt int\n\t\t\t\tif err := depRows.Scan(&id, &cnt); err != nil {\n\t\t\t\t\t_ = depRows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"get dependency counts: scan blocker: %w\", err)\n\t\t\t\t}\n\t\t\t\tif c, ok := result[id]; ok {\n\t\t\t\t\tc.DependencyCount += cnt\n\t\t\t\t}\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(\"get dependency counts: blocker rows: %w\", err)\n\t\t\t}\n\n\t\t\t//nolint:gosec // G201: depTable is hardcoded and inClause contains only ? placeholders.\n\t\t\tblockingRows, err := tx.QueryContext(ctx, fmt.Sprintf(`\n\t\t\t\tSELECT %s AS depends_on_id, COUNT(*) as cnt\n\t\t\t\tFROM %s\n\t\t\t\tWHERE %s AND type = 'blocks'\n\t\t\t\tGROUP BY %s\n\t\t\t`, DepTargetExpr, depTable, depTargetIn(\"\", inClause), DepTargetExpr), args...)\n\t\t\tif err != nil {","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/dependency_queries.go#L463-L499","documentation":"This error is returned by GetDependencyCountsInTx when an SQL row returned by the 'blocked-by counts' aggregate query (SELECT issue_id, COUNT(*) FROM <dep table> WHERE issue_id IN (...) AND type='blocks' GROUP BY issue_id) cannot be scanned into (string, int). The %w wraps the underlying driver scan error. It means the driver returned a row whose column count or types do not match the two expected columns.","triggerScenarios":"Calling GetDependencyCountsInTx (directly or via HydrateReadyRowInTx) against a database whose dependencies/wisp_dependencies schema is non-standard — e.g. issue_id or the COUNT column is NULLable/null, has a different type (TEXT vs VARCHAR fine, but BLOB or NULL fails), or the table was migrated to a different column layout while the binary expects issue_id, count.","commonSituations":"Running a newer beads binary against an older database (or vice versa) after a schema change; a corrupted/partially-migrated Dolt database; custom replicas with altered column types; NULL issue_id values injected by manual SQL edits.","solutions":["Check the wrapped driver error (%w) for the exact column/type mismatch and fix the offending row or column type in dependencies/wisp_dependencies.","Verify the database schema matches the version of the library: run bd doctor / schema migration to align dependencies table columns (issue_id non-null, integer count).","If rows were hand-edited, remove or repair rows with NULL or non-string issue_id values.","If using a remote Dolt backend, confirm client and server versions are compatible; upgrade or downgrade to matching versions.","As a workaround, recompute counts via bd doctor rebuild or re-sync from remote to restore a consistent schema."],"exampleFix":"// before: hand-migrated table with NULLable issue_id\nALTER TABLE dependencies MODIFY issue_id VARCHAR(50) NULL;\n\n// after: restore expected non-null schema so Scan succeeds\nALTER TABLE dependencies MODIFY issue_id VARCHAR(50) NOT NULL;","handlingStrategy":"try-catch","validationCode":"// Go: verify expected schema before calling\nvar cols []struct {\n    Field  string\n    Type   string\n    Null   string\n}\nif err := db.Select(&cols,\n    \"SELECT COLUMN_NAME AS Field, DATA_TYPE AS Type, IS_NULLABLE AS Null FROM information_schema.COLUMNS WHERE TABLE_NAME = 'dependencies'\"); err != nil {\n    return err\n}\nfor _, c := range cols {\n    if c.Field == \"issue_id\" && c.Null == \"YES\" {\n        return fmt.Errorf(\"dependencies.issue_id must be NOT NULL\")\n    }\n}","typeGuard":"func isScanError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"get dependency counts: scan blocker\")\n}","tryCatchPattern":"counts, err := GetDependencyCountsInTx(ctx, tx, ids)\nif err != nil {\n    var scanErr *fmt.ScanError // inspect wrapped driver error\n    if strings.Contains(err.Error(), \"scan blocker\") {\n        // schema drift: run migration/doctor before retrying\n        return fmt.Errorf(\"schema mismatch: %w\", err)\n    }\n    return err\n}","preventionTips":["Never hand-edit dependency rows; use bd commands so types stay valid.","Run schema migrations whenever upgrading the beads binary.","Keep issue_id and depends_on_id columns NOT NULL.","Run bd doctor after restores or imports to catch schema drift early."],"tags":["database","scan-error","schema-mismatch","sql"],"backgroundTag":"sql-row-scan-type-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}