{"record":{"id":"e36db76abf8d60ad","repo":"gastownhall/beads","slug":"ref-too-long","errorCode":null,"errorMessage":"ref too long","messagePattern":"ref too long","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/schema/migration_content_hashes.go","lineNumber":24,"sourceCode":"\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/steveyegge/beads/internal/storage/dberrors\"\n)\n\n// validMigrationRefPattern matches the refs this package builds for AS OF reads\n// (Dolt commit hashes or branch/remote-tracking names like\n// \"remotes/origin/main\"). It mirrors issueops.ValidateRef but is kept local so\n// the schema package — which sits below issueops — has no import-cycle risk.\nvar validMigrationRefPattern = regexp.MustCompile(`^[a-zA-Z0-9_./-]+$`)\n\nfunc validateMigrationRef(ref string) error {\n\tif ref == \"\" {\n\t\treturn fmt.Errorf(\"ref cannot be empty\")\n\t}\n\tif len(ref) > 128 {\n\t\treturn fmt.Errorf(\"ref too long\")\n\t}\n\tif !validMigrationRefPattern.MatchString(ref) {\n\t\treturn fmt.Errorf(\"invalid ref format: %s\", ref)\n\t}\n\treturn nil\n}\n\n// ReadMigrationContentHashes reads version -> content_hash from schema_migrations,\n// either at HEAD (ref == \"\") or AS OF ref (e.g. \"remotes/origin/main\"). NULL/empty\n// hashes are dropped. It returns an error when the table, column, or ref is\n// unavailable; the caller classifies it with RemoteRefUnavailableErr /\n// MissingMigrationObjectErr.\n//\n// Dolt requires a literal ref in AS OF: bind parameters (including inside CONCAT)\n// fail server-side with `unbound variable \"v1\" in query`, so the validated ref is\n// interpolated into the SQL text (bd-6dnrw.27).\nfunc ReadMigrationContentHashes(ctx context.Context, db DBConn, ref string) (map[int]string, error) {\n\tvar (","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/schema/migration_content_hashes.go#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nref := \"remotes/origin/release/2026/Q3/team/very/long/branch/name/that/exceeds/the/limit\"\nschema.ReadMigrationContentHashes(ctx, db, ref)\n// after\nref := \"remotes/origin/release-2026-q3\"\nschema.ReadMigrationContentHashes(ctx, db, ref)","handlingStrategy":"validation","validationCode":"if len(ref) > 128 { return fmt.Errorf(\"ref too long: %d chars\", len(ref)) }","typeGuard":"func validRef(ref string) bool {\n    return len(ref) <= 128 && regexp.MustCompile(`^[a-zA-Z0-9_./-]+$`).MatchString(ref)\n}","tryCatchPattern":null,"preventionTips":["Keep refs to short branch/tag names, not URLs or paths.","Trim programmatically-built ref chains.","Use commit hashes for long identifiers."],"tags":["validation","migration","input-length"],"backgroundTag":"invalid-git-ref","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}