affaan-m/ECC · error · Error
claim requires an owner.
Error message
claim requires an owner.
What it means
Thrown by claimWorkItem when the owner argument is falsy (undefined, null, empty string). Every claim must attribute the item to an owner (agent name or human name) so the board and audit trail stay accurate; an ownerless claim would leave the card assigned to nobody. This is a precondition failure, not a state problem.
Source
Thrown at scripts/lib/control-pane/work-item-mutations.js:58
if (id) {
const item = store.getWorkItemById(id);
if (!item) {
throw new Error(`Work item not found: ${id}`);
}
return item;
}
const { items } = store.listWorkItems({ limit: 100 });
return items.filter(item => !item.owner && isOpenStatus(item.status)).sort((a, b) => priorityRank(a.priority) - priorityRank(b.priority))[0] || null;
}
/**
* Claim an unassigned work item for an agent or human. Sets the owner (and
* optional assigneeKind) and moves the card to running unless an explicit
* status is supplied. Returns { claimed, item } or { claimed: false, reason }.
*/
function claimWorkItem(store, { id, owner, assigneeKind, sessionId, status } = {}) {
if (!owner) {
throw new Error('claim requires an owner.');
}
const kind = assigneeKind ? String(assigneeKind).toLowerCase() : null;
if (kind && !VALID_ASSIGNEE_KINDS.has(kind)) {
throw new Error("assigneeKind must be 'agent' or 'human'.");
}
const target = selectClaimTarget(store, { id });
if (!target) {
return { claimed: false, reason: 'no-unassigned-open-items' };
}
if (!isOpenStatus(target.status)) {
throw new Error(`Work item ${target.id} is already done; cannot claim.`);
}
const metadata = { ...(target.metadata || {}) };
if (kind) {
metadata.assigneeKind = kind;
}
const item = store.upsertWorkItem({
...target,View on GitHub (pinned to 01e15490f0)
Solutions
- Always pass a non-empty owner string (agent id or human name) when calling claimWorkItem.
- In UI/CLI code, validate owner before calling and show a helpful message if empty rather than letting the throw propagate.
- For agent callers, derive owner from the session/agent identity so it can never be empty.
- Add a unit test asserting claimWorkItem throws on empty owner to lock the contract.
Example fix
// before
claimWorkItem(store, { id, owner: name });
// after — guard at the call site
if (!owner || !owner.trim()) {
throw new Error('Please provide a non-empty owner name to claim.');
}
claimWorkItem(store, { id, owner: owner.trim() }); Defensive patterns
Strategy: validation
Validate before calling
if (!owner || typeof owner !== 'string' || !owner.trim()) {
throw new Error('Claim requires a non-empty owner name.');
} Type guard
function isValidOwner(owner) {
return typeof owner === 'string' && owner.trim().length > 0;
} Try / catch
try {
claimWorkItem(store, { id, owner });
} catch (e) {
if (/claim requires an owner/.test(e.message)) { promptForOwner(); return; }
throw e;
} Prevention
- Validate owner at the UI/CLI boundary before calling claimWorkItem.
- Derive owner from agent identity in automated callers.
- Unit-test the empty-owner guard to lock the contract.
When it happens
Trigger: Calling claimWorkItem({ owner: '' }) or claimWorkItem({ id }) with no owner; a UI prompt (window.prompt) that returned null/empty when the user cancelled or left it blank; a CLI flag --owner that was not passed.
Common situations: User pressed Cancel/Enter on the 'Claim as' prompt (eccClaimItem in ui.js returns early on falsy owner but other callers may not); CLI invocation missing the --owner argument; agent loop forgot to pass its session identity.
Related errors
- Work item not found: ${id}
- assigneeKind must be 'agent' or 'human'.
- move requires a work item id.
- Work item ${target.id} is already done; cannot claim.
- Invalid lane '${lane}'. Expected one of ${[...VALID_LANES].j
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/9ab1c9aee89d9fe9.
Report an issue: GitHub.