affaan-m/ECC · error · Error

discussion receipt lookup failed

Error message

discussion receipt lookup failed

What it means

findReceiptComment pages through a discussion's comments via GraphQL node(id) and throws this when `data.node?.comments` is missing. That means the node lookup returned null/undefined or lacked comments — typically because the discussionId is invalid, the token lacks read:discussion scope, or the node is not a Discussion the caller can see.

Solutions

  1. Verify the discussionId (node_id) is correct with a direct query: node(id:...) { ... on Discussion { id number } }
  2. Confirm the token has read:discussion scope for the repository
  3. Log the raw GraphQL response (data and errors) to see whether node is null vs comments missing
  4. Fall back to the REST API GET /repos/{owner}/{repo}/discussions/{number}/comments to cross-check

Example fix

// before
const comments = data.node?.comments;
if (!comments) throw new Error('discussion receipt lookup failed');
// after
if (!data.node) throw new Error(`discussion node ${discussionId} not found or not readable`);
const comments = data.node.comments;
if (!comments) throw new Error(`discussion ${discussionId} returned no comments field: ${JSON.stringify(data)}`);
Defensive patterns

Strategy: try-catch

Validate before calling

// verify the node resolves before paging comments
const probe = await githubGraphql('query($id:ID!){node(id:$id){id ... on Discussion{number}}}', { id: discussionId });
if (!probe.node) throw new Error(`Discussion node ${discussionId} not readable — check id and token scopes`);

Type guard

function isDiscussionComments(node) {
  return node != null && typeof node === 'object'
    && node.comments != null
    && Array.isArray(node.comments.nodes)
    && typeof node.comments.pageInfo?.hasNextPage === 'boolean';
}

Try / catch

try {
  const receipt = await findReceiptComment(discussionId, marker);
} catch (err) {
  if (err.message === 'discussion receipt lookup failed') {
    console.error(`Node ${discussionId} unreadable: check node_id validity and read:discussion scope`);
  }
  throw err;
}

Prevention

When it happens

Trigger: githubGraphql succeeded at the HTTP level but data.node is null (invalid node ID, insufficient permission) or node exists but `comments` field errored/was omitted, so the optional chain yields undefined.

Common situations: A discussion ID from another repository or a stale ID from deleted discussions; token missing the read:discussion scope so node(id) returns null; GitHub returning partial results with in-band errors silently swallowed by the payload.errors check upstream being bypassed is impossible — but a malformed alias/query would produce missing fields.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/77b9e092ec9358aa. Report an issue: GitHub.

Appendix: source

Thrown at scripts/discord/release-announce.mjs:113

  if (!/^\d+$/.test(env.DISCUSSION_NUMBER || '')) throw new Error('discussion number is invalid');
  const response = await request(`https://api.github.com/repos/${env.GITHUB_REPOSITORY}/discussions/${env.DISCUSSION_NUMBER}`, {
    headers: { Authorization: `Bearer ${env.GITHUB_TOKEN}`, Accept: 'application/vnd.github+json' },
  });
  if (!response.ok) throw new Error(`discussion lookup failed (${response.status})`);
  const discussion = await response.json();
  if (discussion.category?.name !== 'Announcements') throw new Error('discussion is not an Announcement');
  return { id: discussion.node_id, title: discussion.title, body: discussion.body, url: discussion.html_url };
}

async function findReceiptComment(discussionId, marker) {
  let cursor = null;
  for (let page = 0; page < 50; page += 1) {
    const data = await githubGraphql(
      `query($id:ID!,$after:String){node(id:$id){... on Discussion{comments(first:100,after:$after){nodes{id body author{login}} pageInfo{hasNextPage endCursor}}}}}`,
      { id: discussionId, after: cursor },
    );
    const comments = data.node?.comments;
    if (!comments) throw new Error('discussion receipt lookup failed');
    const receipt = findDiscussionReceipt(comments.nodes, marker);
    if (receipt) return receipt;
    if (!comments.pageInfo.hasNextPage) return null;
    cursor = comments.pageInfo.endCursor;
  }
  throw new Error('discussion receipt lookup exceeded page budget');
}

async function addReceiptComment(discussionId, body) {
  const data = await githubGraphql(
    `mutation($id:ID!,$body:String!){addDiscussionComment(input:{discussionId:$id,body:$body}){comment{id}}}`,
    { id: discussionId, body },
  );
  return data.addDiscussionComment.comment.id;
}

async function deleteReceiptComment(commentId) {
  await githubGraphql(

View on GitHub (pinned to 8321021c54)