{"record":{"id":"b3d240292570578c","repo":"different-ai/openwork","slug":"plugin-ref-not-found","errorCode":"plugin_ref_not_found","errorMessage":"Could not resolve the requested branch or tag","messagePattern":"Could not resolve the requested branch or tag","errorType":"error_code","errorClass":"ApiError","httpStatus":404,"severity":"error","filePath":"apps/server/src/claude-plugin-bundle.ts","lineNumber":197,"sourceCode":"        ref: source.treeSegments.slice(0, index).join(\"/\"),\n        dir: index < source.treeSegments.length ? source.treeSegments.slice(index).join(\"/\") : null,\n      });\n    }\n  } else {\n    candidates.push({ ref: await resolveDefaultBranch(source), dir: null });\n  }\n\n  let lastError: unknown = null;\n  for (const candidate of candidates) {\n    try {\n      const tree = await fetchRepoTree(source, candidate.ref);\n      return { ref: candidate.ref, dir: candidate.dir, tree };\n    } catch (error) {\n      lastError = error;\n    }\n  }\n  if (lastError instanceof Error) throw lastError;\n  throw new ApiError(404, \"plugin_ref_not_found\", \"Could not resolve the requested branch or tag\");\n}\n\n// Find the plugin root: the given subdir, the repo root, or the shallowest\n// directory containing `.claude-plugin/plugin.json`.\nfunction locatePluginRoot(tree: TreeEntry[], dir: string | null): string {\n  const manifestPaths = tree\n    .map((entry) => entry.path)\n    .filter((path) => path === \".claude-plugin/plugin.json\" || path.endsWith(\"/.claude-plugin/plugin.json\"));\n  if (dir) {\n    const normalized = dir.replace(/\\/+$/, \"\");\n    const expected = `${normalized}/.claude-plugin/plugin.json`;\n    if (!manifestPaths.includes(expected)) {\n      throw new ApiError(404, \"plugin_manifest_not_found\", `No .claude-plugin/plugin.json found under ${normalized}/`);\n    }\n    return `${normalized}/`;\n  }\n  if (manifestPaths.length === 0) {\n    throw new ApiError(404, \"plugin_manifest_not_found\", \"No .claude-plugin/plugin.json found in this repository\");","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/server/src/claude-plugin-bundle.ts#L179-L215","documentation":"resolveRefAndTree resolves the requested ref (branch or tag) against a list of candidate refs, attempting each one; if every candidate fails, it rethrows the last error, and only when there was no Error at all does it throw this 404 ApiError. It signals that the requested branch or tag could not be resolved to a commit tree for the repository.","triggerScenarios":"Requesting a plugin bundle with a ref (branch/tag) that does not exist in the repository, or an empty/unrecognized ref string, such that no candidate resolved and no underlying Error was captured.","commonSituations":"Default branch renamed from 'main' to 'master' or vice versa; tag deleted or not yet created; typo like 'tree/mainn'; repo where all candidate refs (main/master/HEAD) fail to resolve.","solutions":["Check the ref in the URL against the repository's actual branches/tags on GitHub.","Use a commit SHA or an existing tag instead of a branch name for reproducible installs.","If relying on the default branch, confirm the repo's default branch name (main vs master).","Inspect the wrapped lastError (if a prior error was rethrown) to distinguish network/403 issues from a truly unknown ref."],"exampleFix":"// before\nGET /plugin/tree/mian/<dir>          // typo, no such branch\n// after\nGET /plugin/tree/main/<dir>          // or /tree/v1.2.0/<dir> for a tag","handlingStrategy":"validation","validationCode":"const ref = \"v1.2.0\"; // resolve beforehand\nconst exists = await fetch(`https://api.github.com/repos/${owner}/${repo}/git/ref/tags/${ref}`).then(r => r.ok);\nif (!exists) throw new Error(`ref ${ref} not found`);","typeGuard":null,"tryCatchPattern":"try {\n  await installPlugin(url);\n} catch (e) {\n  if (isApiError(e) && e.code === \"plugin_ref_not_found\") {\n    // fall back to the repo default branch\n  }\n}","preventionTips":["Use tags or commit SHAs rather than mutable branch names.","Confirm the branch/tag exists on GitHub before constructing the URL.","Remember the default branch may be master, not main.","Handle repo default-branch renames in automation."],"tags":["github","git-ref","plugin-install","http"],"backgroundTag":"git-ref-not-found","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}