affaan-m/ECC · error · Error

discussion number is invalid

Error message

discussion number is invalid

What it means

discussionFromGitHub throws this before making any network call when DISCUSSION_NUMBER is not a string of digits. The regex /^\d+$/ guards the REST URL construction, since a non-numeric number would produce a malformed endpoint and a confusing 404/400 from GitHub.

Solutions

  1. Set DISCUSSION_NUMBER to the bare numeric discussion id (e.g. 12)
  2. Strip a leading '#' and extract the number if you only have a URL: DISCUSSION_NUMBER=$(basename "$DISCUSSION_URL")
  3. Confirm the env var is exported and reachable inside the script's process
  4. Echo the value in CI to see exactly what the script receives

Example fix

// before
if (!/^\d+$/.test(env.DISCUSSION_NUMBER || '')) throw new Error('discussion number is invalid');
// after
const rawNumber = (env.DISCUSSION_NUMBER || '').trim().replace(/^#/, '');
if (!/^\d+$/.test(rawNumber)) throw new Error(`discussion number is invalid: "${env.DISCUSSION_NUMBER}"`);
Defensive patterns

Strategy: validation

Validate before calling

const raw = (process.env.DISCUSSION_NUMBER || '').trim().replace(/^#/, '');
if (!/^\d+$/.test(raw)) throw new Error(`DISCUSSION_NUMBER must be numeric, got: ${process.env.DISCUSSION_NUMBER}`);

Type guard

function isValidDiscussionNumber(v) {
  return typeof v === 'string' && /^\d+$/.test(v.trim());
}

Try / catch

try {
  const discussion = await discussionFromGitHub();
} catch (err) {
  if (err.message === 'discussion number is invalid') {
    console.error(`DISCUSSION_NUMBER="${process.env.DISCUSSION_NUMBER}" — pass the bare numeric id, not a URL`);
  }
  throw err;
}

Prevention

When it happens

Trigger: DISCUSSION_NUMBER env var is empty, unset, contains non-digit characters (e.g. a full URL like https://github.com/owner/repo/discussions/12, a '#12' reference, or trailing whitespace).

Common situations: Workflow passes the discussion URL instead of its number; value pasted with a leading '#' or spaces; DISCUSSION_NUMBER not exported in the job step; typo setting it to the issue number of a different entity.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

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

  const created = await githubGraphql(
    `mutation($repo:ID!,$cat:ID!,$title:String!,$body:String!){createDiscussion(input:{repositoryId:$repo,categoryId:$cat,title:$title,body:$body}){discussion{id title body url category{name}}}}`,
    { repo: repository.id, cat: category.id, title, body },
  );
  return created.createDiscussion.discussion;
}

function discussionFromEnvironment() {
  if (env.DISCUSSION_CATEGORY !== 'Announcements') throw new Error('discussion is not an Announcement');
  return {
    id: env.DISCUSSION_ID,
    title: env.DISCUSSION_TITLE,
    body: env.DISCUSSION_BODY,
    url: env.DISCUSSION_URL,
  };
}

async function discussionFromGitHub() {
  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');

View on GitHub (pinned to 8321021c54)