{"record":{"id":"104554818b77ed79","repo":"gastownhall/beads","slug":"db-getallconfig-scan-w","errorCode":null,"errorMessage":"db: GetAllConfig: scan: %w","messagePattern":"db: GetAllConfig: scan: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/domain/db/config.go","lineNumber":119,"sourceCode":"\nfunc (r *configSQLRepositoryImpl) DeleteConfig(ctx context.Context, key string) error {\n\tif _, err := r.runner.ExecContext(ctx, \"DELETE FROM config WHERE `key` = ?\", key); err != nil {\n\t\treturn fmt.Errorf(\"db: DeleteConfig %s: %w\", key, err)\n\t}\n\treturn nil\n}\n\nfunc (r *configSQLRepositoryImpl) GetAllConfig(ctx context.Context) (map[string]string, error) {\n\trows, err := r.runner.QueryContext(ctx, \"SELECT `key`, value FROM config\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"db: GetAllConfig: %w\", err)\n\t}\n\tdefer rows.Close()\n\tout := make(map[string]string)\n\tfor rows.Next() {\n\t\tvar k, v string\n\t\tif err := rows.Scan(&k, &v); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"db: GetAllConfig: scan: %w\", err)\n\t\t}\n\t\tout[k] = v\n\t}\n\tif err := rows.Err(); err != nil {\n\t\treturn nil, fmt.Errorf(\"db: GetAllConfig: read: %w\", err)\n\t}\n\treturn out, nil\n}\n\nfunc (r *configSQLRepositoryImpl) GetCustomTypes(ctx context.Context) ([]string, error) {\n\tfromTable, err := r.readCustomTypesTable(ctx)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tfromDB := fromTable\n\tif len(fromDB) == 0 {\n\t\tfromConfig, err := r.readCustomTypesConfig(ctx)","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/domain/db/config.go#L101-L137","documentation":"This error wraps a rows.Scan failure while iterating GetAllConfig results — the query succeeded but a row's columns could not be decoded into two strings. This usually means a row contains NULL or a non-string value in the `key` or value column, or a driver-level decode error.","triggerScenarios":"Calling GetAllConfig when a config row has NULL in `key` or value (violating the NOT-NULL expectation of the scan into string), or the driver fails to convert a column to string during rows.Scan(&k, &v).","commonSituations":"Manually edited or externally written config rows with NULL values; schema drift where the config table lost its NOT NULL constraints after a migration; data written by an incompatible tool directly into the Dolt database.","solutions":["Inspect the config table for NULL keys or values (e.g. via a SQL client) and repair or delete those rows","Re-apply the expected schema constraints on config (`key` and value NOT NULL)","Replace the corrupted rows via SetConfig so both value and projections are rewritten","If many rows are bad, export/repair the database and re-open","Restore from a known-good backup if the table was corrupted externally"],"exampleFix":"// before\nvar k, v string\nrows.Scan(&k, &v) // panics silently on NULL\n// after\nvar k, v sql.NullString\nif err := rows.Scan(&k, &v); err != nil {\n\treturn nil, fmt.Errorf(\"db: GetAllConfig: scan: %w\", err)\n}","handlingStrategy":"validation","validationCode":"rows, _ := db.Query(\"SELECT COUNT(*) FROM config WHERE `key` IS NULL OR value IS NULL\")\nvar bad int\nrows.Scan(&bad)\nif bad > 0 {\n\treturn fmt.Errorf(\"%d config rows have NULL key/value; repair before reading\", bad)\n}","typeGuard":null,"tryCatchPattern":"if _, err := repo.GetAllConfig(ctx); err != nil && strings.Contains(err.Error(), \"scan\") {\n\t// NULL or malformed row: repair rows or restore backup before retry\n\treturn repairConfigNullRows(ctx)\n}","preventionTips":["Never write config rows manually with NULL key/value","Keep NOT NULL constraints on config(`key`, value) through migrations","Use SetConfig instead of direct SQL inserts","Back up the database before external tools touch it"],"tags":["database","scan","null-value","data-integrity"],"backgroundTag":"row-scan-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}