gastownhall/beads · error
invalid strategy %q (want %q or %q)
Error message
invalid strategy %q (want %q or %q)
What it means
ValidateConflictStrategy rejects any conflict resolution strategy other than the two dolt row-level strategies, "ours" (ConflictStrategyOurs) or "theirs" (ConflictStrategyTheirs). The library defines only these two valid values because dolt's row-conflict resolution supports exactly these choices. The error echoes the rejected value and the two accepted values to make the mistake obvious.
Source
Thrown at internal/storage/versioncontrolops/conflicts.go:70
}
// ValidateConflictTable rejects anything that is not a plain SQL identifier,
// so a table name can be safely interpolated into a conflict query. Conflict
// table names come from dolt_conflicts (or an operator's --table) and MySQL
// cannot parameterize an identifier, so they are validated instead. It reuses
// the package's existing table-name gate, which ResolveConflicts already
// trusts for exactly this.
func ValidateConflictTable(table string) error {
return validateTableName(table)
}
// ValidateConflictStrategy accepts only the two dolt strategies.
func ValidateConflictStrategy(strategy string) error {
switch strategy {
case ConflictStrategyOurs, ConflictStrategyTheirs:
return nil
default:
return fmt.Errorf("invalid strategy %q (want %q or %q)", strategy, ConflictStrategyOurs, ConflictStrategyTheirs)
}
}
// SupportsRowResolve reports whether table can be resolved row by row.
func SupportsRowResolve(table string) bool {
_, ok := conflictRowKeyColumn[table]
return ok
}
// splitConflictColumn splits a dolt conflict column into its side and field
// name. ok is false for columns that belong to no side (dolt does not emit
// any today, but a future column must not be silently treated as a field).
func splitConflictColumn(col string) (side, field string, ok bool) {
for _, s := range conflictSides {
if strings.HasPrefix(col, s) {
return strings.TrimSuffix(s, "_"), strings.TrimPrefix(col, s), true
}
}View on GitHub (pinned to 71377f2769)
Solutions
- Use the exported constants ConflictStrategyOurs or ConflictStrategyTheirs instead of string literals
- Normalize input with strings.ToLower(strings.TrimSpace(s)) before passing it
- Validate user/config-supplied strategies up front with ValidateConflictStrategy and surface the message to the user
- Check for typos against the exact values shown in the error message
Example fix
// before n, err := ResolveConflictRows(ctx, db, "issues", keys, "Ours") // after n, err := ResolveConflictRows(ctx, db, "issues", keys, versioncontrolops.ConflictStrategyOurs)
Defensive patterns
Strategy: validation
Validate before calling
if s := strings.ToLower(strings.TrimSpace(strategy)); s != versioncontrolops.ConflictStrategyOurs && s != versioncontrolops.ConflictStrategyTheirs {
return fmt.Errorf("strategy must be %q or %q, got %q", versioncontrolops.ConflictStrategyOurs, versioncontrolops.ConflictStrategyTheirs, strategy)
} Type guard
func isValidStrategy(s string) bool {
return s == versioncontrolops.ConflictStrategyOurs || s == versioncontrolops.ConflictStrategyTheirs
} Try / catch
if err := versioncontrolops.ValidateConflictStrategy(strategy); err != nil {
return fmt.Errorf("bad strategy argument: %w", err) // invalid input, not transient
} Prevention
- Always pass the exported constants, never raw strings
- Normalize and validate user/config input before calling
- Add a unit test enumerating valid strategy values
When it happens
Trigger: Calling ResolveConflictRows, MergeWithStrategy, or TestValidateConflictStrategy with a strategy string that is not exactly ConflictStrategyOurs or ConflictStrategyTheirs — e.g. typos ("our", "theirs ", "both", "manual"), uppercase variants ("OURS"), or an empty string.
Common situations: Hard-coding a strategy literal from memory instead of using the exported constants; importing a strategy value from another library (e.g. git merge strategy names like "ort" or "recursive"); reading the strategy from config/CLI flags without validating against the constants; case mismatch after lowercasing user input fails.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- per-row conflict resolution is not supported for table %s; r
- invalid --dolt-auto-commit=%q (valid: off, on, batch)
- remote target %s is non-empty but is neither a bare git repo
- ExternalDoltConfig: Port %d out of range [1, 65535]
- dolt metadata path %s is not a directory
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/99d65271b893be65.
Report an issue: GitHub.