{"record":{"id":"4dfa5ad2920b1a8a","repo":"mislav/hub","slug":"can-t-parse-range-s-s","errorCode":null,"errorMessage":"Can't parse range %s..%s","messagePattern":"Can't parse range (.+?)\\.\\.(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"git/git.go","lineNumber":175,"sourceCode":"\toutput, err := listCmd.Output()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"Can't load rev-list for %s\", ref)\n\t}\n\n\treturn outputLines(output), nil\n}\n\nfunc NewRange(a, b string) (*Range, error) {\n\tparseCmd := gitCmd(\"rev-parse\", \"-q\", a, b)\n\tparseCmd.Stderr = nil\n\toutput, err := parseCmd.Output()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := outputLines(output)\n\tif len(lines) != 2 {\n\t\treturn nil, fmt.Errorf(\"Can't parse range %s..%s\", a, b)\n\t}\n\treturn &Range{lines[0], lines[1]}, nil\n}\n\ntype Range struct {\n\tA string\n\tB string\n}\n\nfunc (r *Range) IsIdentical() bool {\n\treturn strings.EqualFold(r.A, r.B)\n}\n\nfunc (r *Range) IsAncestor() bool {\n\tcmd := gitCmd(\"merge-base\", \"--is-ancestor\", r.A, r.B)\n\treturn cmd.Success()\n}\n","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/mislav/hub/blob/5c547ed804368763064e51f3990851e267e88edd/git/git.go#L157-L193","documentation":"NewRange() reads merge-base/heads via a git command expected to output exactly two lines (the two endpoints of the range) and builds a Range{A,B}. When the output doesn't have exactly 2 lines, the library can't parse the range and throws this error naming a..b.","triggerScenarios":"Calling git.NewRange(a, b) (via sync) when the underlying git command yields 0, 1, or 3+ lines — typically because one of the refs is invalid, points to the same commit, or output parsing assumptions break on unusual repo states.","commonSituations":"Comparing a branch with itself; refs that don't exist locally (no fetch); empty repositories with no commits; refs resolving to identical commits producing degenerate output.","solutions":["Ensure both a and b exist: git rev-parse a b","Fetch the remote branch before computing the range","Check the two refs differ; same-commit ranges are meaningless","Inspect raw `git merge-base`/`rev-list` output to see the real state"],"exampleFix":"// before\nrng, err := git.NewRange(base, head)\n// after\nif shaA, err := git.Ref(base); err != nil || shaA == mustRef(head) {\n    return fmt.Errorf(\"invalid or identical refs %s..%s\", base, head)\n}\nrng, err := git.NewRange(base, head)","handlingStrategy":"validation","validationCode":"shaA, errA := exec.Command(\"git\", \"rev-parse\", a).Output()\nshaB, errB := exec.Command(\"git\", \"rev-parse\", b).Output()\nif errA != nil || errB != nil || bytes.Equal(bytes.TrimSpace(shaA), bytes.TrimSpace(shaB)) {\n    return fmt.Errorf(\"invalid or degenerate range %s..%s\", a, b)\n}","typeGuard":null,"tryCatchPattern":"rng, err := git.NewRange(a, b)\nif err != nil {\n    return fmt.Errorf(\"cannot parse range %s..%s; verify both refs exist and differ\", a, b)\n}","preventionTips":["Confirm both refs resolve and differ before building ranges","Fetch remote branches before range computation","Skip range logic in empty repos or same-commit comparisons","Log raw underlying git output when debugging"],"tags":["git","range","parsing","refs"],"backgroundTag":"unexpected-git-output","analyzedSha":"5c547ed804368763064e51f3990851e267e88edd","analyzedAt":"2026-09-01T03:34:15.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}