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

  1. Shorten the ref to a valid branch/tag/remote-ref under 128 characters.
  2. Use a commit hash or short ref that resolves to the same history point.
  3. Trim any accidental URL/prefix so only the ref portion remains.
  4. 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

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


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