gastownhall/beads · error
ref too long
Error message
ref too long
What it means
validateMigrationRef enforces a 128-character maximum on migration refs used in AS OF queries. Longer refs are rejected because they are interpolated into SQL literals (AS OF requires a literal, not a bind param) and to bound input size. The library throws this to keep the injected literal safe and sane.
Source
Thrown at internal/storage/schema/migration_content_hashes.go:24
"fmt"
"regexp"
"strings"
"github.com/steveyegge/beads/internal/storage/dberrors"
)
// validMigrationRefPattern matches the refs this package builds for AS OF reads
// (Dolt commit hashes or branch/remote-tracking names like
// "remotes/origin/main"). It mirrors issueops.ValidateRef but is kept local so
// the schema package — which sits below issueops — has no import-cycle risk.
var validMigrationRefPattern = regexp.MustCompile(`^[a-zA-Z0-9_./-]+$`)
func validateMigrationRef(ref string) error {
if ref == "" {
return fmt.Errorf("ref cannot be empty")
}
if len(ref) > 128 {
return fmt.Errorf("ref too long")
}
if !validMigrationRefPattern.MatchString(ref) {
return fmt.Errorf("invalid ref format: %s", ref)
}
return nil
}
// ReadMigrationContentHashes reads version -> content_hash from schema_migrations,
// either at HEAD (ref == "") or AS OF ref (e.g. "remotes/origin/main"). NULL/empty
// hashes are dropped. It returns an error when the table, column, or ref is
// unavailable; the caller classifies it with RemoteRefUnavailableErr /
// MissingMigrationObjectErr.
//
// Dolt requires a literal ref in AS OF: bind parameters (including inside CONCAT)
// fail server-side with `unbound variable "v1" in query`, so the validated ref is
// interpolated into the SQL text (bd-6dnrw.27).
func ReadMigrationContentHashes(ctx context.Context, db DBConn, ref string) (map[int]string, error) {
var (View on GitHub (pinned to 71377f2769)
Solutions
- Shorten the ref to a valid branch/tag/remote-ref under 128 characters.
- Use a commit hash or short ref that resolves to the same history point.
- Trim any accidental URL/prefix so only the ref portion remains.
- If legitimately longer refs are needed, raise the limit upstream in the validator (library change).
Example fix
// before ref := "remotes/origin/release/2026/Q3/team/very/long/branch/name/that/exceeds/the/limit" schema.ReadMigrationContentHashes(ctx, db, ref) // after ref := "remotes/origin/release-2026-q3" schema.ReadMigrationContentHashes(ctx, db, ref)
Defensive patterns
Strategy: validation
Validate before calling
if len(ref) > 128 { return fmt.Errorf("ref too long: %d chars", len(ref)) } Type guard
func validRef(ref string) bool {
return len(ref) <= 128 && regexp.MustCompile(`^[a-zA-Z0-9_./-]+$`).MatchString(ref)
} Prevention
- Keep refs to short branch/tag names, not URLs or paths.
- Trim programmatically-built ref chains.
- Use commit hashes for long identifiers.
When it happens
Trigger: Calling ReadMigrationContentHashes with a ref longer than 128 chars — e.g. a fully-qualified remote ref with long paths, an accidental paste of a full URL or commit message into the ref field, or concatenated branch prefixes.
Common situations: Copy-paste of a URL or long identifier instead of a ref name; programmatically built refs like "remotes/origin/team/very/long/...path"; generated branch names from CI exceeding the limit.
Related errors
- --source-db and --output are required
- legacy SQLite source %q must be a regular file
- issue %s has invalid %s boolean
- ref cannot be empty
- invalid ref: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/e36db76abf8d60ad.
Report an issue: GitHub.