affaan-m/ECC · error · Error
Announcements discussion category is required
Error message
Announcements discussion category is required
What it means
createOrFindReleaseDiscussion requires a discussion category literally named 'Announcements' in the target repository, and throws this error when no such category exists. GitHub discussion categories are repo-level settings the script cannot create via this path, so it fails fast instead of posting into a wrong category.
Solutions
- Create or rename a category to exactly 'Announcements' in the repo: Settings > Discussions, or gh api to edit discussion categories
- Verify discussions are enabled on the repository
- Check for case/whitespace differences between the repo's category name and the expected 'Announcements'
- Consider making the required category name configurable via env var
Example fix
// before
const category = repository.discussionCategories.nodes.find(item => item.name === 'Announcements');
if (!category) throw new Error('Announcements discussion category is required');
// after
const wanted = env.DISCUSSION_CATEGORY || 'Announcements';
const category = repository.discussionCategories.nodes.find(item => item.name === wanted);
if (!category) throw new Error(`Discussion category "${wanted}" is required; found: ${repository.discussionCategories.nodes.map(c => c.name).join(', ')}`); Defensive patterns
Strategy: validation
Validate before calling
// preflight: confirm the category exists
const cats = await fetch(`https://api.github.com/repos/${owner}/${repo}`, { headers: { Authorization: `Bearer ${token}` } });
// GraphQL check:
// query { repository(owner:"o",name:"r"){ discussionCategories(first:50){ nodes{ name } } } }
// assert nodes includes 'Announcements' before invoking the announce script Type guard
function hasAnnouncementsCategory(repository) {
return repository?.discussionCategories?.nodes?.some(c => c.name === 'Announcements') === true;
} Try / catch
try {
const discussion = await createOrFindReleaseDiscussion();
} catch (err) {
if (err.message === 'Announcements discussion category is required') {
console.error('Repo discussion categories: enable Discussions and create an "Announcements" category');
}
throw err;
} Prevention
- Create the 'Announcements' discussion category in repo Settings > Discussions as part of repo bootstrap
- Document the required category in the workflow README/setup checklist
- Compare category names case-insensitively in the script to tolerate renames
- Store the category id in config as a fallback to name matching
When it happens
Trigger: The repository's discussionCategories.nodes contains no item with name === 'Announcements' after an existing release discussion was not found — the script is about to create a new discussion but cannot pick a category.
Common situations: Repo has discussions enabled but only default categories like 'General', 'Ideas', 'Q&A'; 'Announcements' category was renamed (e.g. 'Announcement'); discussions feature entirely disabled on the repo; running against a fork or fresh repo without the category set up.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- discussion is not an Announcement
- discussion receipt lookup failed
- announcement delivered; pending receipt cleanup requires…
- Choose at least one guided harness: Claude, Codex, or Kimi.
- config must be a JSON object
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/00c0c384e129ce9b.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/discord/release-announce.mjs:74
`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 },
);
const discussions = pageData.repository.discussions;
existing = findReleaseDiscussion(discussions.nodes, marker);
if (!discussions.pageInfo.hasNextPage) break;
cursor = discussions.pageInfo.endCursor;
}
if (existing) return existing;
const category = repository.discussionCategories.nodes.find(item => item.name === 'Announcements');
if (!category) throw new Error('Announcements discussion category is required');
const title = `${release.name || release.tag_name} release`;
const body = [marker, release.body || '', `Release: ${release.html_url}`].filter(Boolean).join('\n\n');
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,
};
}View on GitHub (pinned to 8321021c54)