gastownhall/beads · error

wisp id set: scan: %w

Error message

wisp id set: scan: %w

What it means

Thrown when rows.Scan fails decoding an id column from the wisp batch SELECT into a string. Like the deferred-wake scan error, this indicates a row whose id cannot be converted — NULL id, incompatible driver type, or corrupted row. Rows are closed before returning to release the cursor.

Source

Thrown at internal/storage/issueops/wisp_routing.go:98

			end = len(ids)
		}
		batch := ids[start:end]
		placeholders := make([]string, len(batch))
		args := make([]any, len(batch))
		for i, id := range batch {
			placeholders[i] = "?"
			args[i] = id
		}
		q := fmt.Sprintf("SELECT id FROM wisps WHERE id IN (%s)", strings.Join(placeholders, ","))
		rows, err := tx.QueryContext(ctx, q, args...)
		if err != nil {
			return nil, fmt.Errorf("wisp id set: %w", err)
		}
		for rows.Next() {
			var id string
			if err := rows.Scan(&id); err != nil {
				_ = rows.Close()
				return nil, fmt.Errorf("wisp id set: scan: %w", err)
			}
			set[id] = struct{}{}
		}
		_ = rows.Close()
		if err := rows.Err(); err != nil {
			return nil, fmt.Errorf("wisp id set: rows: %w", err)
		}
	}
	return set, nil
}

// partitionByWispSet splits ids into (wispIDs, permIDs) using the provided
// wisp-id set. If wispSet is nil the caller must populate it first via
// WispIDSetInTx; this helper does no I/O.
func partitionByWispSet(ids []string, wispSet map[string]struct{}) (wispIDs, permIDs []string) {
	for _, id := range ids {
		if _, isWisp := wispSet[id]; isWisp {
			wispIDs = append(wispIDs, id)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Find and fix the row with the malformed id in the wisps table.
  2. Enforce id VARCHAR NOT NULL PRIMARY KEY on the wisps table.
  3. Update the driver if the id column type/charset conversion is mishandled.
  4. Run storage integrity checks to detect further corruption.

Example fix

// before
id VARCHAR(255) NULL
// after
id VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL PRIMARY KEY
Defensive patterns

Strategy: validation

Validate before calling

rows, err := db.Query("SELECT id FROM wisps WHERE id IS NULL")
if err != nil { return err }
defer rows.Close()
if rows.Next() { return errors.New("wisps rows with NULL id found: repair table before routing") }

Try / catch

if err != nil {
    if strings.Contains(err.Error(), "converting NULL to string") {
        return fmt.Errorf("corrupt wisps row (NULL id): repair wisps table")
    }
    return err
}

Prevention

When it happens

Trigger: Calling WispIDSetInTx when a row in wisps has a NULL or non-string id, or the driver mis-declares the id column type/charset so Scan cannot convert it.

Common situations: Manually inserted rows with NULL id; Dolt/MySQL driver charset mismatches on the id column; binary-typed id columns after schema tampering.

Related errors


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