affaan-m/ECC · error · Error
release lookup failed
Error message
release lookup failed (${response.status}) What it means
releaseFromGitHub fetches a GitHub release by tag via the REST API and throws this error when `response.ok` is false (any non-2xx status). The status code is embedded in the message to distinguish 404 (no release for that tag) from 401/403 (auth) and other failures.
Solutions
- Verify the tag actually has a published (non-draft) GitHub release: gh release view <tag>
- Check the response status in the message: 404 -> fix tag/RELEASE_TAG or create the release; 401 -> fix GITHUB_TOKEN; 403 -> wait out rate limit or check token scopes
- Ensure GITHUB_REPOSITORY is set correctly (owner/repo)
- Print the response body for the detailed GitHub error before throwing
Example fix
// before
if (!response.ok) throw new Error(`release lookup failed (${response.status})`);
// after
if (!response.ok) throw new Error(`release lookup failed (${response.status}): ${await response.text()}`); Defensive patterns
Strategy: validation
Validate before calling
// before running, verify the release exists
const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/');
const tag = process.env.RELEASE_TAG || process.env.GITHUB_REF_NAME;
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}/releases/tags/${encodeURIComponent(tag)}`, { headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` } });
if (res.status === 404) throw new Error(`No published release for tag ${tag} in ${owner}/${repo} — drafts are not returned by this endpoint`); Try / catch
try {
const release = await releaseFromGitHub();
} catch (err) {
const m = /release lookup failed \((\d+)\)/.exec(err.message);
if (m && m[1] === '404') throw new Error(`Release for tag not found; publish the release first: ${err.message}`);
throw err;
} Prevention
- Publish the GitHub release (not draft) before announcing
- Keep RELEASE_TAG in sync with the actual git tag / GITHUB_REF_NAME
- Check gh release view <tag> locally before triggering the workflow
- Include the response body in error messages for the real GitHub error
When it happens
Trigger: GET https://api.github.com/repos/{owner}/{repo}/releases/tags/{tag} returning 404 (no published release exists for RELEASE_TAG/GITHUB_REF_NAME), 401 (bad GITHUB_TOKEN), 403 (rate limited or forbidden), 422 (malformed tag).
Common situations: Running the announce script on a tag with only a draft release (drafts are not reachable by tag endpoint without push access/preview header); RELEASE_TAG env var mismatched with actual tag; token missing repo scope; tag name needing encodeURIComponent mismatches if env already encoded.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- discussion lookup failed
- announcement delivered; pending receipt cleanup requires…
- Announcements discussion category is required
- Control-plane request failed
- Discord request failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9bad28b7370bcfa5.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/discord/release-announce.mjs:47
async function githubGraphql(query, variables) {
const response = await request('https://api.github.com/graphql', {
method: 'POST',
headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
});
if (!response.ok) throw new Error(`GitHub GraphQL request failed (${response.status})`);
const payload = await response.json();
if (payload.errors) throw new Error('GitHub GraphQL returned errors');
return payload.data;
}
async function releaseFromGitHub() {
const [owner, repo] = env.GITHUB_REPOSITORY.split('/');
const tag = env.RELEASE_TAG || env.GITHUB_REF_NAME;
const response = await request(`https://api.github.com/repos/${owner}/${repo}/releases/tags/${encodeURIComponent(tag)}`, {
headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}`, Accept: 'application/vnd.github+json' },
});
if (!response.ok) throw new Error(`release lookup failed (${response.status})`);
return response.json();
}
async function createOrFindReleaseDiscussion() {
const release = await releaseFromGitHub();
const [owner, name] = env.GITHUB_REPOSITORY.split('/');
const marker = releaseMarker(release.tag_name);
const data = await githubGraphql(
`query($owner:String!,$name:String!){repository(owner:$owner,name:$name){id discussionCategories(first:25){nodes{id name}}}}`,
{ owner, name },
);
const repository = data.repository;
let cursor = null;
let existing = null;
for (let page = 0; page < 50 && !existing; page += 1) {
const pageData = await githubGraphql(
`query($owner:String!,$name:String!,$after:String){repository(owner:$owner,name:$name){discussions(first:100,after:$after,orderBy:{field:CREATED_AT,direction:DESC}){nodes{id title body url category{name}} pageInfo{hasNextPage endCursor}}}}`,
{ owner, name, after: cursor },View on GitHub (pinned to 8321021c54)