gastownhall/beads · error

scan same-content events in %s: %w

Error message

scan same-content events in %s: %w

What it means

In InsertDerivedEventReturningID, a dedup lookup selects ids of existing same-content events; this wraps the QueryContext failure itself (before any rows are read). The query uses `<=>` (NULL-safe equality) against the derived events table routed by `table`; any SQL-level error — bad table name, missing column, connection failure — surfaces here.

Source

Thrown at internal/storage/issueops/derivedid.go:137

		for _, p := range []*sql.NullString{&e.OldValue, &e.NewValue, &e.Comment} {
			if !p.Valid {
				*p = str("")
			}
		}
	}
	digest := rowid.Digest([]sql.NullString{
		str(e.IssueID), str(string(e.EventType)), str(e.Actor),
		e.OldValue, e.NewValue, e.Comment, str(e.CreatedAt),
	})
	taken := make(map[string]bool)
	rows, err := tx.QueryContext(ctx, fmt.Sprintf(`
		SELECT id FROM %s
		WHERE issue_id = ? AND event_type = ? AND actor = ?
		  AND old_value <=> ? AND new_value <=> ? AND comment <=> ?
		  AND created_at = ?`, table),
		e.IssueID, string(e.EventType), e.Actor, e.OldValue, e.NewValue, e.Comment, e.CreatedAt)
	if err != nil {
		return "", fmt.Errorf("scan same-content events in %s: %w", table, err)
	}
	for rows.Next() {
		var id string
		if err := rows.Scan(&id); err != nil {
			_ = rows.Close()
			return "", fmt.Errorf("scan same-content events in %s: %w", table, err)
		}
		taken[id] = true
	}
	_ = rows.Close()
	if err := rows.Err(); err != nil {
		return "", fmt.Errorf("scan same-content events in %s: %w", table, err)
	}

	id := firstFreeDerivedID(table, digest, taken)
	if _, err := tx.ExecContext(ctx, fmt.Sprintf(`
		INSERT INTO %s (id, issue_id, event_type, actor, old_value, new_value, comment, created_at)
		VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, table),

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run schema migrations so the events table has all expected columns.
  2. Verify the table routing constant matches an existing derived events table.
  3. Check tx health / connection state; retry outside the failed transaction if it's aborted.
  4. Inspect the wrapped driver error (`%w` chain) for the precise SQL failure (e.g. 'Unknown column').

Example fix

// before: column missing on old schema
_, err := tx.QueryContext(ctx, fmt.Sprintf(`SELECT id FROM %s WHERE ... AND comment <=> ?`, table), ...)
// after: migrate first, e.g. `bd migrate` / ensure ALTER TABLE applied before use
if err := migrate(ctx, db); err != nil { return err }
_, err := tx.QueryContext(ctx, fmt.Sprintf(`SELECT id FROM %s WHERE ... AND comment <=> ?`, table), ...)
Defensive patterns

Strategy: try-catch

Validate before calling

if err := ctx.Err(); err != nil { return err }
cols, err := tableColumns(tx, table)
if err != nil { return err }
for _, c := range []string{"id", "issue_id", "event_type", "actor", "old_value", "new_value", "comment", "created_at"} {
	if !slices.Contains(cols, c) {
		return fmt.Errorf("events table %s missing column %s; migrate first", table, c)
	}
}

Type guard

func isQueryErr(err error) bool {
	var me *mysql.MySQLError // dolt speaks mysql protocol
	return errors.As(err, &me)
}

Try / catch

id, err := InsertDerivedEvent(ctx, tx, e)
if err != nil {
	if strings.Contains(err.Error(), "Unknown column") || strings.Contains(err.Error(), "doesn't exist") {
		return fmt.Errorf("schema drift on %s; run migrations: %w", table, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling AddCommentEventInTx or InsertDerivedEvent against a table missing the expected columns (id, issue_id, event_type, actor, old_value, new_value, comment, created_at), or with a dead/cancelled connection or wrong `table` routing constant.

Common situations: Older databases lacking newer event-table columns; passing an unsupported table constant; Dolt connection dropped inside a long transaction.

Understand the failure class

Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.

Related errors


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