{"record":{"id":"371d4592bd48f0be","repo":"gastownhall/beads","slug":"scan-inbound-dependency-w","errorCode":null,"errorMessage":"scan inbound dependency: %w","messagePattern":"scan inbound dependency: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete.go","lineNumber":261,"sourceCode":"\t\t}\n\t\tbatch := set.All[i:end]\n\t\tbatchInClause, batchArgs := buildSQLInClause(batch)\n\n\t\tfor _, depTable := range []string{\"dependencies\", \"wisp_dependencies\"} {\n\t\t\trows, err := tx.QueryContext(ctx,\n\t\t\t\tfmt.Sprintf(`SELECT issue_id FROM %s WHERE %s`, depTable, depTargetIn(\"\", batchInClause)),\n\t\t\t\tbatchArgs...)\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(\"count inbound dependencies from %s: %w\", depTable, err)\n\t\t\t}\n\t\t\tfor rows.Next() {\n\t\t\t\tvar issID string\n\t\t\t\tif err := rows.Scan(&issID); err != nil {\n\t\t\t\t\t_ = rows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"scan inbound dependency: %w\", err)\n\t\t\t\t}\n\t\t\t\tif !deletedSet[issID] {\n\t\t\t\t\tdepsCount++\n\t\t\t\t}\n\t\t\t}\n\t\t\t_ = rows.Close()\n\t\t\tif err := rows.Err(); err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"iterate inbound dependencies from %s: %w\", depTable, err)\n\t\t\t}\n\t\t}\n\t}\n\n\tresult.DependenciesCount = depsCount\n\tresult.LabelsCount = labelsCount\n\tresult.EventsCount = eventsCount\n\tresult.DeletedCount = len(set.RegularIDs) + len(set.WispIDs)\n\n\tif dryRun {","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete.go#L243-L279","documentation":"DeleteResolvedSetInTx aborts when scanning a row of the inbound-dependency result set fails — the issue_id column could not be read into a string. This indicates unexpected column types or a NULL in a column the query expects to be a non-NULL string, wrapped with the driver's scan error.","triggerScenarios":"Calling DeleteIssuesInTx/DeleteInTx when a dependency table's issue_id/target column contains NULL or a non-string value, typically from schema drift, manual edits, or a driver returning different column types.","commonSituations":"Hand-edited or externally imported databases with NULL issue_id values; a custom driver that returns []byte vs string incompatibly; corrupted rows after a crash.","solutions":["Find the row(s) with NULL/non-string issue_id in the named dependency table and repair or delete them.","Run a schema/data integrity check (bd doctor) on the database.","Restore from backup if rows are corrupted.","Ensure imports/conversions always populate issue_id NOT NULL."],"exampleFix":"// before\n// NULL issue_id row corrupts delete\n// after\nUPDATE dependencies SET issue_id = '<recovered-id>' WHERE issue_id IS NULL;\n-- or delete the orphan edge:\nDELETE FROM dependencies WHERE issue_id IS NULL;","handlingStrategy":"validation","validationCode":"// detect corrupt edges before deleting\nrows, err := db.QueryContext(ctx,\n    `SELECT COUNT(*) FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL`)\nif err != nil {\n    return err\n}\nvar bad int\n_ = rows.Scan(&bad)\nif bad > 0 {\n    return fmt.Errorf(\"%d dependency rows have NULL ids; repair before delete\", bad)\n}","typeGuard":null,"tryCatchPattern":"err := batchDelete(ctx, tx, ids)\nif err != nil && strings.Contains(err.Error(), \"scan inbound dependency\") {\n    return fmt.Errorf(\"corrupt dependency row (NULL/non-string id); run integrity repair: %w\", err)\n}","preventionTips":["Enforce NOT NULL on issue_id/target columns in schema and imports.","Never hand-edit database rows; use bd commands.","Run periodic integrity checks (bd doctor) on shared databases."],"tags":["go","storage","sql","data-integrity","scan-error"],"backgroundTag":"sql-scan-null-column","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}