ruvnet/ruflo · error · Error
delegation-depth-exhausted
Error message
delegation-depth-exhausted
What it means
delegateEnvelope() implements bounded delegation: a parent envelope may spawn children only while parent.delegationDepth (defaulting to 0) is > 0. Each delegation decrements the depth, so attempting to delegate from an envelope at depth 0 — or one that never set the field — throws Error('delegation-depth-exhausted').
Source
Thrown at v3/@claude-flow/security/src/policy/envelope.ts:93
[child.delegationDepth, parent.delegationDepth],
[child.expiresAt, parent.expiresAt],
];
return listChecks.every(Boolean)
&& numericChecks.every(([next, current]) => (
current === undefined
? true
: next !== undefined && next <= current
))
&& !(child.network === true && parent.network !== true)
&& !(child.destructive === true && parent.destructive !== true);
}
export function delegateEnvelope(
parent: CapabilityEnvelope,
child: CapabilityEnvelope,
): CapabilityEnvelope {
if ((parent.delegationDepth ?? 0) <= 0) {
throw new Error('delegation-depth-exhausted');
}
const reduced = {
...parent,
...child,
delegationDepth: Math.min(
child.delegationDepth ?? Number.MAX_SAFE_INTEGER,
(parent.delegationDepth ?? 0) - 1,
),
expiresAt: Math.min(
child.expiresAt ?? Number.MAX_SAFE_INTEGER,
parent.expiresAt ?? Number.MAX_SAFE_INTEGER,
),
};
if (!isEnvelopeReduction(parent, reduced)) throw new Error('capability-envelope-cannot-grow');
return reduced;
}
View on GitHub (pinned to fa13ee4ad6)
Solutions
- Set delegationDepth on the root envelope to the maximum chain length you need (e.g. 3 for root -> agent -> sub-agent -> sub-sub-agent).
- Check (parent.delegationDepth ?? 0) > 0 before attempting to delegate, and treat 0 as 'leaf only'.
- When a hierarchy deepens, mint a fresh root envelope with a higher depth rather than delegating past the cap.
Example fix
// before
const root = mintEnvelope({ principal: 'orchestrator', tools: [...] }); // delegationDepth undefined -> 0
const child = delegateEnvelope(root, { principal: 'worker', ... }); // throws
// after
const root = mintEnvelope({ principal: 'orchestrator', delegationDepth: 3, tools: [...] });
const child = delegateEnvelope(root, { principal: 'worker', ... }); Defensive patterns
Strategy: validation
Validate before calling
if ((parent.delegationDepth ?? 0) <= 0) {
throw new Error(
`envelope ${parent.id} is a leaf (delegationDepth 0) — cannot delegate`
);
}
const child = delegateEnvelope(parent, childSpec); Type guard
function canDelegate(parent: CapabilityEnvelope): boolean {
return (parent.delegationDepth ?? 0) > 0;
} Try / catch
try {
return delegateEnvelope(parent, child);
} catch (err) {
if (err instanceof Error && err.message === 'delegation-depth-exhausted') {
return requestFreshRootEnvelope(parent.id); // mint from the authority instead
}
throw err;
} Prevention
- Set delegationDepth on root envelopes to your planned hierarchy depth plus one.
- Treat depth 0/undefined as 'leaf-only' and short-circuit before calling delegateEnvelope.
- When adding tiers of sub-agents, re-mint the root with higher depth rather than exceeding the cap.
When it happens
Trigger: Creating a root envelope without delegationDepth and immediately calling delegateEnvelope(parent, child); an agent chain longer than the root's initial depth (grandchild of a depth-1 envelope); re-delegating an already-exhausted envelope in retry logic.
Common situations: Templates for capability envelopes that omit delegationDepth; adding a second tier of sub-agents to a hierarchy whose envelopes were minted with depth for only one tier; defensive envelopes intentionally issued with depth 0 being reused for delegation.
Related errors
- depth-underflow
- scope-expired
- scope-cannot-grow
- capability-envelope-cannot-grow
- approval issuance requires an authenticated human identity a
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/1b8e1e0c26652497.
Report an issue: GitHub.