gastownhall/beads · error

inserting type %q: %w

Error message

inserting type %q: %w

What it means

This error wraps a failed INSERT IGNORE INTO custom_types (name) VALUES (?) while backfilling configured custom issue types during migration. INSERT IGNORE normally swallows duplicate rows, so a surfaced error is a real SQL failure — table missing, connection dropped, privilege denied, or another constraint.

Source

Thrown at internal/storage/schema/backfill.go:112

	var value string
	err := db.QueryRowContext(ctx, "SELECT `value` FROM config WHERE `key` = 'types.custom'").Scan(&value)
	if err == sql.ErrNoRows {
		return false, nil
	}
	if err != nil {
		return false, err
	}
	if value == "" {
		return false, nil
	}

	wrote := false
	// ParseTypesConfigValue already trims elements and drops empties.
	for _, name := range issueops.ParseTypesConfigValue(value) {
		res, err := db.ExecContext(ctx, "INSERT IGNORE INTO custom_types (name) VALUES (?)", name)
		if err != nil {
			return wrote, fmt.Errorf("inserting type %q: %w", name, err)
		}
		if n, err := res.RowsAffected(); err == nil && n > 0 {
			wrote = true
		}
	}
	return wrote, nil
}

func backfillCustomStatuses(ctx context.Context, db DBConn) (bool, error) {
	var count int
	if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM custom_statuses").Scan(&count); err != nil {
		return false, err
	}
	if count > 0 {
		return false, nil
	}

	var value string

View on GitHub (pinned to 71377f2769)

Solutions

  1. Ensure all numbered migrations run before backfill so custom_types exists, then re-run MigrateUp.
  2. Fix DB grants: the user needs INSERT on custom_types.
  3. Restore Dolt connectivity and retry the migration; the count-gated backfill is safe to repeat.
  4. Validate the 'types.custom' config value and config table integrity if failures persist.

Example fix

// before: any single bad insert aborts the backfill
res, err := db.ExecContext(ctx, "INSERT IGNORE INTO custom_types (name) VALUES (?)", name)
if err != nil {
	return wrote, fmt.Errorf("inserting type %q: %w", name, err)
}
// after: ensure the table exists before inserting (only if migrations can't be reordered)
db.ExecContext(ctx, "CREATE TABLE IF NOT EXISTS custom_types (name VARCHAR(255) PRIMARY KEY)")
res, err := db.ExecContext(ctx, "INSERT IGNORE INTO custom_types (name) VALUES (?)", name)
Defensive patterns

Strategy: retry

Validate before calling

// Ensure custom_types exists and config is readable before backfill triggers
var n int
if err := db.QueryRowContext(ctx, `SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'custom_types'`).Scan(&n); err != nil || n == 0 {
	return fmt.Errorf("custom_types missing; run migrations")
}
var v sql.NullString
if err := db.QueryRowContext(ctx, "SELECT `value` FROM config WHERE `key` = 'types.custom'").Scan(&v); err != nil && err != sql.ErrNoRows {
	return fmt.Errorf("config unreadable: %w", err)
}

Try / catch

err := migrateUp(ctx)
if err != nil && strings.Contains(err.Error(), "inserting type ") {
	if isTransient(err) {
		err = migrateUp(ctx) // count-gated backfill resumes safely
	}
}

Prevention

When it happens

Trigger: backfillCustomTypes iterates ParseTypesConfigValue(config['types.custom']) and one INSERT IGNORE returns a driver error: custom_types table doesn't exist, INSERT privilege missing, connection killed, or context cancelled mid-loop.

Common situations: Migrating a database where migrations creating custom_types were skipped; running under a limited DB role; server restart mid-backfill; corrupted config table producing odd values (parsing itself never errors — ParseTypesConfigValue trims/drops empties).

Related errors


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