{"record":{"id":"9a5df15d07718522","repo":"gastownhall/beads","slug":"failed-to-scan-issue-id-w-9a5df1","errorCode":null,"errorMessage":"failed to scan issue id: %w","messagePattern":"failed to scan issue id: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dolt/issues.go","lineNumber":817,"sourceCode":"\t}\n\tif err != sql.ErrNoRows {\n\t\treturn fmt.Errorf(\"failed to check issue_counter for prefix %q: %w\", prefix, err)\n\t}\n\n\t// No counter row yet. Scan existing issues to find the highest numeric suffix.\n\tlikePattern := prefix + \"-%\"\n\trows, err := tx.QueryContext(ctx, \"SELECT id FROM issues WHERE id LIKE ?\", likePattern)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to query existing issues for prefix %q: %w\", prefix, err)\n\t}\n\tdefer rows.Close()\n\n\tmaxNum := 0\n\tprefixDash := prefix + \"-\"\n\tfor rows.Next() {\n\t\tvar id string\n\t\tif err := rows.Scan(&id); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to scan issue id: %w\", err)\n\t\t}\n\t\t// Strip the prefix and attempt to parse the remainder as an integer.\n\t\tsuffix := strings.TrimPrefix(id, prefixDash)\n\t\tif suffix == id {\n\t\t\t// id did not start with prefix- (should not happen given LIKE, but be safe)\n\t\t\tcontinue\n\t\t}\n\t\tvar num int\n\t\tif _, parseErr := fmt.Sscanf(suffix, \"%d\", &num); parseErr == nil && fmt.Sprintf(\"%d\", num) == suffix {\n\t\t\tif num > maxNum {\n\t\t\t\tmaxNum = num\n\t\t\t}\n\t\t}\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn fmt.Errorf(\"failed to iterate existing issues for prefix %q: %w\", prefix, err)\n\t}\n","sourceCodeStart":799,"sourceCodeEnd":835,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dolt/issues.go#L799-L835","documentation":"While iterating rows from the issue id scan, rows.Scan(&id) can fail if a row's id column is NULL or has an unexpected type; that failure is wrapped here. It indicates malformed or unexpected data in the issues table rather than a query error.","triggerScenarios":"seedCounterFromExistingIssuesTx scanning an issues row whose id is NULL or non-string (schema corruption, manual edits, incompatible migration).","commonSituations":"Hand-edited databases, interrupted migrations, or imports that wrote rows violating the schema (NULL primary keys).","solutions":["Inspect the issues table for rows with NULL or malformed id values and remove/repair them","Run bd doctor for integrity checks","Restore the database from a known-good backup if rows are corrupt","Re-run the create/seed operation after cleanup"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Detect rows with NULL/invalid ids\nconst bad = await query(\"SELECT COUNT(*) FROM issues WHERE id IS NULL OR id = ''\");\nif (bad > 0) throw new Error(`${bad} corrupt issue rows; repair before use`);","typeGuard":"function hasValidId(row) {\n  return typeof row.id === \"string\" && /^[^\\s]+-\\d+$/.test(row.id);\n}","tryCatchPattern":"try {\n  await bd.create(title);\n} catch (e) {\n  if (String(e.message).includes(\"failed to scan issue id\")) {\n    // run integrity repair / bd doctor before retrying\n  } else throw e;\n}","preventionTips":["Never hand-edit database rows directly","Use bd import/export tooling instead of raw writes","Run integrity checks (bd doctor) after crashes or restores","Keep schema migrations consistent across versions"],"tags":["database","scan","corruption","counter"],"backgroundTag":"row-scan-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}