gastownhall/beads · error

failed to scan diff: %w

Error message

failed to scan diff: %w

What it means

This error wraps a rows.Scan failure while decoding one dolt_diff() result row into the ten expected string columns (from/to id, diff type, title, description, status, priority). Scan fails when a column's value cannot be converted to the target string variable. Note the query already COALESCEs id columns, so failures usually come from unexpected column shapes or engine-level conversion issues.

Source

Thrown at internal/storage/issueops/diff.go:53

	rows, err := tx.QueryContext(ctx, query)
	if err != nil {
		return nil, fmt.Errorf("failed to get diff: %w", err)
	}
	defer rows.Close()

	var entries []*storage.DiffEntry
	for rows.Next() {
		var fromID, toID, diffType string
		var fromTitle, toTitle, fromDesc, toDesc, fromStatus, toStatus *string
		var fromPriority, toPriority *int

		if err := rows.Scan(&fromID, &toID, &diffType,
			&fromTitle, &toTitle,
			&fromDesc, &toDesc,
			&fromStatus, &toStatus,
			&fromPriority, &toPriority); err != nil {
			return nil, fmt.Errorf("failed to scan diff: %w", err)
		}

		entry := &storage.DiffEntry{
			DiffType: diffType,
		}

		if toID != "" {
			entry.IssueID = toID
		} else {
			entry.IssueID = fromID
		}

		// Build old value for modified/removed
		if diffType != "added" && fromID != "" {
			entry.OldValue = &types.Issue{
				ID: fromID,
			}
			if fromTitle != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check the wrapped cause to see which column failed to convert
  2. Verify the Dolt server version matches what the library expects; upgrade/downgrade if dolt_diff's output shape changed
  3. Check the issues table schema at the diffed refs for changed column types
  4. If a column type changed (e.g. priority now numeric), cast it to CHAR in the query before scanning

Example fix

// before
&fromPriority, &toPriority); err != nil {
    return nil, fmt.Errorf("failed to scan diff: %w", err)
}
// after
// in the query: CAST(from_priority AS CHAR) as from_priority, CAST(to_priority AS CHAR) as to_priority
&fromPriority, &toPriority); err != nil {
    return nil, fmt.Errorf("failed to scan diff (column type mismatch?): %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// verify dolt_diff column shape matches expectations before scanning
cols, err := queryColumns(ctx, tx, fmt.Sprintf("SELECT * FROM dolt_diff('%s','%s','issues') LIMIT 1", from, to))
if err != nil {
    return err
}
if len(cols) != 10 {
    return fmt.Errorf("dolt_diff returned %d columns; library expects 10 — check Dolt version", len(cols))
}

Try / catch

entries, err := issueops.DiffInTx(ctx, tx, from, to)
if err != nil {
    if strings.Contains(err.Error(), "failed to scan diff") {
        log.Errorf("diff row decode failed; verify Dolt version and issues-table column types: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: A dolt_diff result row contains a value the driver cannot decode into a string (NULL in a non-COALESCE'd column with an incompatible driver, unexpected column type from a Dolt version change, or a column-count mismatch after a schema/engine update).

Common situations: Dolt server version differences changing dolt_diff column types; schema changes on issues (e.g. priority becoming an int) that the driver refuses to scan into string; corrupted rows.

Related errors


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