affaan-m/ECC · error
Issue # is not open
Error message
Issue #${issue.number} is not open What it means
assertIssueClaimable validates that an issue can be claimed: the underlying GitHub issue must be in the 'open' state. It throws when the issue is closed (or has an unexpected state), preventing agents from claiming work on issues that are finished or rejected. A further check rejects issues already claimed by another owner.
Solutions
- Check the issue on GitHub — if closed intentionally, pick a different issue.
- If the issue should be open, reopen it (`gh issue reopen <n> -R <owner>/<name>`) and retry the claim.
- Re-sync/re-fetch the issue to get the latest state before claiming.
- If using a shim, ensure it returns state as the lowercase string 'open'.
Example fix
// before
applyClaim('org/repo', 42); // issue 42 is closed
// after
runGh(['issue', 'reopen', '42', '-R', 'org/repo']);
applyClaim('org/repo', 42); Defensive patterns
Strategy: try-catch
Validate before calling
const issue = getIssue(repo, n);
if (String(issue.state || '').toLowerCase() !== 'open') {
throw new Error(`Issue #${n} is ${issue.state}; only open issues can be claimed`);
} Type guard
const isOpenIssue = (i) => typeof i?.state === 'string' && i.state.toLowerCase() === 'open';
Try / catch
try {
applyClaim(repo, n);
} catch (e) {
if (e.message.endsWith('is not open')) {
console.error(`Issue #${n} is closed. Reopen it (gh issue reopen ${n}) or pick another issue.`);
} else { throw e; }
} Prevention
- Re-fetch the issue immediately before claiming to get current state.
- Filter issue lists to state=open before attempting claims.
- Handle races where issues close between listing and claiming.
- Ensure shims return state as lowercase 'open'.
When it happens
Trigger: Calling applyClaim (directly or via the claim workflow) for an issue whose state is 'closed' — fetched from getIssue/listIssues — or whose state field is missing/case-mismatched in a shim.
Common situations: A collaborator closed the issue between listing and claiming, automation auto-closed stale issues, a bot closed issues on branch merge, or a custom shim returns state as 'OPEN' in an unexpected format or omits it.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Refusing to : managed destination changed before removal…
- a top-level committed transaction is required
- Another ECC process is updating Claude settings
- Another Nasiko lifecycle operation is already in progress…
- Another Nasiko lifecycle operation won lock acquisition
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/8dd46458424ce4d6.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/github-coordination/state.js:211
action,
status: state.status,
owner: state.owner || null,
branch: state.branch || null,
validation: state.validation || 'pending',
review: state.review || 'not-requested',
project: summarizeProjectProjection(state, policy),
dependencies: Array.isArray(state.dependencies) ? state.dependencies : [],
tasks: Array.isArray(state.tasks) ? state.tasks : [],
labels: normalizeLabels(issue.labels),
workItemId: `github-${slugifySegment(repo)}-epic-${issue.number}`,
lastActionAt: state.lastActionAt || null,
lastSyncAt: state.lastSyncAt || null,
};
}
function assertIssueClaimable(issue, state) {
if (String(issue.state || '').toLowerCase() !== 'open') {
throw new Error(`Issue #${issue.number} is not open`);
}
if (state.status === 'claimed') {
throw new Error(`Issue #${issue.number} is already claimed by ${state.owner || 'unknown'}`);
}
}
function verifyDependenciesClosed(repo, dependencyNumbers, options = {}, allIssues = null) {
if (!Array.isArray(dependencyNumbers) || dependencyNumbers.length === 0) {
return [];
}
const issueList = allIssues || listIssues(repo, { ...options, state: 'all', limit: options.limit || 200 });
const closed = [];
for (const dependencyNumber of dependencyNumbers) {
const issue = findIssueByNumber(issueList, dependencyNumber);
if (!issue) {
process.stderr.write(`[github-coordination] Warning: dependency issue #${dependencyNumber} not found in issue list (may be in a different repo or beyond limit)\n`);View on GitHub (pinned to 8321021c54)