affaan-m/ECC · error · Error
Issue #${issue.number} is already claimed by ${state.owner |
Error message
Issue #${issue.number} is already claimed by ${state.owner || 'unknown'} What it means
Thrown by assertIssueClaimable() when the issue is open but the coordination state already records status === 'claimed'. The message identifies the current owner (or 'unknown' if state.owner is missing) so the caller can coordinate rather than double-claim.
Source
Thrown at scripts/lib/github-coordination/state.js:215
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`);
} else if (String(issue.state || '').toLowerCase() === 'closed') {
closed.push(dependencyNumber);
}
}View on GitHub (pinned to 01e15490f0)
Solutions
- Confirm the current owner: read the coordination block in the issue body or call getCoordinationState(issue).
- If the prior claim is stale, release it first (set status back to 'available' and post the coordination comment) before retrying.
- If actively owned, pick a different issue or wait for the owner to publish/release.
- Add a pre-check: if (state.status === 'claimed') skip or queue.
Example fix
// before
assertIssueClaimable(issue, state);
// after
if (state.status === 'claimed') {
console.log(`#${issue.number} already owned by ${state.owner || 'unknown'}; skipping`);
return null;
}
assertIssueClaimable(issue, state); Defensive patterns
Strategy: validation
Validate before calling
function isClaimable(issue, state) {
return String(issue.state || '').toLowerCase() === 'open'
&& state.status !== 'claimed';
}
if (!isClaimable(issue, state)) {
console.log(`#${issue.number} owned by ${state.owner || 'unknown'}`);
} Type guard
function isUnclaimed(state) {
return state && state.status !== 'claimed';
} Try / catch
try {
assertIssueClaimable(issue, state);
} catch (err) {
if (/already claimed/) {
return { skipped: true, owner: state.owner };
}
throw err;
} Prevention
- Use a single coordination dispatcher (e.g. serialized queue) to avoid races.
- Refresh getCoordinationState(issue) right before claiming.
- Build a release/unclaim flow that clears status: claimed in the issue body.
When it happens
Trigger: assertIssueClaimable(issue, state) where state.status === 'claimed'. state is typically returned by getCoordinationState() which parses the embedded coordination block from the issue body.
Common situations: Two agents race to claim the same issue; a previous claim's comment is still embedded in the issue body; the claim was released locally but the issue body still shows status: claimed; manual edit of the coordination marker left status as 'claimed'.
Related errors
- Issue #${issue.number} is not open
- baseline is not the active harness configuration
- ${flagName} requires a value
- Unknown argument: ${arg}
- Missing issue number.
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/d8ca6802d84bcc13.
Report an issue: GitHub.