{"record":{"id":"a6eb1b90f18e1497","repo":"gastownhall/beads","slug":"scan-neighbor-w","errorCode":null,"errorMessage":"scan neighbor: %w","messagePattern":"scan neighbor: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/issueops/delete_role.go","lineNumber":278,"sourceCode":"\t\tinClause, args := buildSQLInClause(ids[i:end])\n\t\tdoubled := append(append([]interface{}{}, args...), args...)\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, %s AS depends_on_id FROM %s WHERE issue_id IN (%s) OR %s`,\n\t\t\t\t\tDepTargetExpr, depTable, inClause, depTargetIn(\"\", inClause)),\n\t\t\t\tdoubled...)\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(\"query neighbors from %s: %w\", depTable, err)\n\t\t\t}\n\t\t\tfor rows.Next() {\n\t\t\t\tvar source, target string\n\t\t\t\tif err := rows.Scan(&source, &target); err != nil {\n\t\t\t\t\t_ = rows.Close()\n\t\t\t\t\treturn nil, fmt.Errorf(\"scan neighbor: %w\", err)\n\t\t\t\t}\n\t\t\t\tfor _, candidate := range [2]string{source, target} {\n\t\t\t\t\tif candidate == \"\" || deleting[candidate] {\n\t\t\t\t\t\tcontinue\n\t\t\t\t\t}\n\t\t\t\t\tneighborIDs[candidate] = true\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 neighbors from %s: %w\", depTable, err)\n\t\t\t}\n\t\t}\n\t}\n\tif len(neighborIDs) == 0 {\n\t\treturn nil, nil\n\t}\n","sourceCodeStart":260,"sourceCodeEnd":296,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/issueops/delete_role.go#L260-L296","documentation":"While streaming neighbor rows, rows.Scan failed to decode the two string columns (issue_id, depends_on_id) returned by the neighbors query. Like the dependents scan error, this indicates the row shape deviates from what the query assumes — typically NULLs or a non-string column produced by the DepTargetExpr expression. Rows are closed before returning and the delete aborts.","triggerScenarios":"deleteNeighborsInTx iterates rows from the dependencies/wisp_dependencies neighbor query and Scan(&source, &target) errors — NULL column values, driver type coercion failure, or altered SELECT arity.","commonSituations":"Hand-edited or legacy dependency rows with NULL issue_id/target; custom or drifted DepTargetExpr; backend driver returning columns in unexpected types.","solutions":["Locate and repair the offending row (NULL issue_id or NULL target in the named dependency table)","Check whether DepTargetExpr was modified and still returns a plain string","Confirm the dependency tables were not written by an incompatible schema version","Re-run the delete after the data fix; it fails on the same row until repaired"],"exampleFix":"// before: row with NULL issue_id crashes the scan\n// after: clean orphaned edges\nDELETE FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL;","handlingStrategy":"validation","validationCode":"// pre-audit for malformed neighbor edges\nrows, _ := db.Query(\"SELECT issue_id, target_id FROM dependencies WHERE issue_id IS NULL OR target_id IS NULL\")\n// fix any hits before deleting, or Scan will fail on them","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"scan neighbor\") {\n    // locate the malformed dependency row and repair, then re-run delete\n}","preventionTips":["Route all edge writes through the library API","Integrity-check dependency tables after imports or manual surgery","Keep DepTargetExpr unmodified unless you also fix scan arity/types","Align schema versions across all writer processes"],"tags":["database","sql","scan-error","data-integrity"],"backgroundTag":"sql-scan-type-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}