gastownhall/beads · error

invalid table name: %s

Error message

invalid table name: %s

What it means

validateTableName rejects names that do not match validTablePattern. Because table names are interpolated into backtick-quoted SQL statements, characters that could escape the quoting (backticks, quotes, special symbols) are forbidden. The offending name appears in the error message.

Source

Thrown at internal/storage/dolt/history.go:51

	if len(name) > 64 {
		return fmt.Errorf("database name too long")
	}
	if !validDatabasePattern.MatchString(name) {
		return fmt.Errorf("invalid database name: %s", name)
	}
	return nil
}

// validateTableName checks if a table name is safe to use in queries
func validateTableName(table string) error {
	if table == "" {
		return fmt.Errorf("table name cannot be empty")
	}
	if len(table) > 64 {
		return fmt.Errorf("table name too long")
	}
	if !validTablePattern.MatchString(table) {
		return fmt.Errorf("invalid table name: %s", table)
	}
	return nil
}

// issueHistory represents an issue at a specific point in history
type issueHistory struct {
	Issue      *types.Issue
	CommitHash string
	Committer  string
	CommitDate time.Time
}

// getIssueHistory returns the complete history of an issue
func (s *DoltStore) getIssueHistory(ctx context.Context, issueID string) ([]*issueHistory, error) {
	// Wrap in a subquery to avoid Dolt's max1Row optimization on PK lookup.
	// dolt_history_* tables return multiple rows per PK (one per commit),
	// but the query planner incorrectly assumes WHERE id=? returns one row.
	rows, err := s.queryContext(ctx, `

View on GitHub (pinned to 71377f2769)

Solutions

  1. Sanitize the table name to plain identifier characters (letters, digits, underscores) before passing it to any dolt query helper.
  2. Never accept raw user input as a table name; map user choices to a fixed allowlist of known table names.
  3. If the name comes from configuration, validate the config value at load time against the same pattern.

Example fix

// before
table := r.URL.Query().Get("table") // "issues; DROP TABLE x"
store.QueryHistory(ctx, id, table)
// after
var allowed = map[string]bool{"issues": true, "wisps": true}
table := r.URL.Query().Get("table")
if !allowed[table] { return fmt.Errorf("unknown table") }
store.QueryHistory(ctx, id, table)
Defensive patterns

Strategy: validation

Validate before calling

var tablePattern = regexp.MustCompile(`^[A-Za-z0-9_]+$`)
func validTableName(t string) bool { return tablePattern.MatchString(t) }
if !validTableName(table) { return fmt.Errorf("table name %q contains invalid characters", table) }

Prevention

When it happens

Trigger: Passing a table name containing backticks, quotes, spaces, semicolons, slashes, or other non-identifier characters into a query path guarded by validateTableName.

Common situations: User-supplied table/filter input reaching an internal query; dynamically built table names from external config with path-like values ('org/repo'); injection attempts being safely rejected by this guard.

Related errors


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