{"record":{"id":"1fd87bafad3bd3a5","repo":"tinyhumansai/openhuman","slug":"label-ref-not-found-ref","errorCode":null,"errorMessage":"${label} ref not found: ${ref}","messagePattern":"(.+?) ref not found: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/release/generate-release-notes.mjs","lineNumber":161,"sourceCode":"}\n\nfunction resolveStartRef(repo, from) {\n  if (from !== 'latest-release') {\n    return from;\n  }\n\n  const tag = runGh(['release', 'view', '--repo', repo, '--json', 'tagName', '--jq', '.tagName']);\n  if (!tag) {\n    throw new Error(`Could not resolve latest GitHub Release tag for ${repo}`);\n  }\n  return tag;\n}\n\nfunction assertRefExists(ref, label) {\n  try {\n    runGit(['rev-parse', '--verify', `${ref}^{commit}`], { allowFailure: true });\n  } catch {\n    throw new Error(`${label} ref not found: ${ref}`);\n  }\n}\n\nexport function extractPullRequestNumbers(subject) {\n  const matches = [...String(subject || '').matchAll(/\\(#(\\d+)\\)/g)];\n  return [...new Set(matches.map((match) => Number(match[1])).filter(Number.isInteger))];\n}\n\nexport function parseGitLog(logText) {\n  if (!logText.trim()) {\n    return [];\n  }\n\n  return logText\n    .split('\\x1e')\n    .map((entry) => entry.trim())\n    .filter(Boolean)\n    .map((entry) => {","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/release/generate-release-notes.mjs#L143-L179","documentation":"assertRefExists() validates every resolved start/end ref with `git rev-parse --verify <ref>^{commit}` (allowFailure swallows the non-zero exit); when the local clone cannot resolve the ref to a commit, it throws `<label> ref not found: <ref>`. This guards the later git log range from producing garbage or empty notes.","triggerScenarios":"A --from/--to value that does not exist locally: a tag that was never fetched, a remote-only branch given without the origin/ prefix, a typo'd or truncated SHA, or a release tag resolved from GitHub that lies outside a shallow clone's history.","commonSituations":"CI checkouts with fetch-depth: 1 or --no-tags so rev-parse cannot see the tag; fresh local clones; copying a tag name from a different fork; using main when only origin/main exists in detached-HEAD CI contexts.","solutions":["Fetch full tags/history: git fetch --tags origin (add --unshallow in shallow CI clones), then re-run","Confirm the ref resolves exactly as the script does: git rev-parse --verify '<ref>^{commit}' must print a SHA","Use fully-qualified refs: origin/main instead of main, or the full 40-char SHA","Check spelling against git tag --list"],"exampleFix":"# before (CI shallow clone, tag not fetched)\n- run: node scripts/release/generate-release-notes.mjs --from v1.2.3\n\n# after\n- run: git fetch --tags --unshallow origin\n- run: node scripts/release/generate-release-notes.mjs --from v1.2.3","handlingStrategy":"validation","validationCode":"git fetch --tags origin >/dev/null 2>&1\nfor ref in \"$FROM\" \"${TO:-latest-tag}\"; do\n  [ \"$ref\" = 'latest-tag' ] && ref=$(git describe --tags --abbrev=0)\n  git rev-parse --verify --quiet \"${ref}^{commit}\" >/dev/null \\\n    || { echo \"ref '$ref' not resolvable locally\" >&2; exit 1; }\ndone","typeGuard":null,"tryCatchPattern":null,"preventionTips":["fetch --tags (and --unshallow in CI) as a workflow step before generating notes","prefer full SHAs or qualified refs (origin/main) in automation","run the same rev-parse assertion as a preflight"],"tags":["git","release-notes","validation","ci"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}