gastownhall/beads · error

db: GetAllConfig: scan: %w

Error message

db: GetAllConfig: scan: %w

What it means

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.

Source

Thrown at internal/storage/domain/db/config.go:119

func (r *configSQLRepositoryImpl) DeleteConfig(ctx context.Context, key string) error {
	if _, err := r.runner.ExecContext(ctx, "DELETE FROM config WHERE `key` = ?", key); err != nil {
		return fmt.Errorf("db: DeleteConfig %s: %w", key, err)
	}
	return nil
}

func (r *configSQLRepositoryImpl) GetAllConfig(ctx context.Context) (map[string]string, error) {
	rows, err := r.runner.QueryContext(ctx, "SELECT `key`, value FROM config")
	if err != nil {
		return nil, fmt.Errorf("db: GetAllConfig: %w", err)
	}
	defer rows.Close()
	out := make(map[string]string)
	for rows.Next() {
		var k, v string
		if err := rows.Scan(&k, &v); err != nil {
			return nil, fmt.Errorf("db: GetAllConfig: scan: %w", err)
		}
		out[k] = v
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("db: GetAllConfig: read: %w", err)
	}
	return out, nil
}

func (r *configSQLRepositoryImpl) GetCustomTypes(ctx context.Context) ([]string, error) {
	fromTable, err := r.readCustomTypesTable(ctx)
	if err != nil {
		return nil, err
	}

	fromDB := fromTable
	if len(fromDB) == 0 {
		fromConfig, err := r.readCustomTypesConfig(ctx)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the config table for NULL keys or values (e.g. via a SQL client) and repair or delete those rows
  2. Re-apply the expected schema constraints on config (`key` and value NOT NULL)
  3. Replace the corrupted rows via SetConfig so both value and projections are rewritten
  4. If many rows are bad, export/repair the database and re-open
  5. Restore from a known-good backup if the table was corrupted externally

Example fix

// before
var k, v string
rows.Scan(&k, &v) // panics silently on NULL
// after
var k, v sql.NullString
if err := rows.Scan(&k, &v); err != nil {
	return nil, fmt.Errorf("db: GetAllConfig: scan: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

rows, _ := db.Query("SELECT COUNT(*) FROM config WHERE `key` IS NULL OR value IS NULL")
var bad int
rows.Scan(&bad)
if bad > 0 {
	return fmt.Errorf("%d config rows have NULL key/value; repair before reading", bad)
}

Try / catch

if _, err := repo.GetAllConfig(ctx); err != nil && strings.Contains(err.Error(), "scan") {
	// NULL or malformed row: repair rows or restore backup before retry
	return repairConfigNullRows(ctx)
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/104554818b77ed79. Report an issue: GitHub.