ruvnet/ruflo · error · Error
invalid-policy-request
Error message
invalid-policy-request
What it means
Before evaluating anything, PolicyEngine.evaluate() calls validateRequest(): the request must carry identity.id (truthy), identity.type, and action.type. Missing or partial requests throw Error('invalid-policy-request') — the engine will not evaluate an anonymous or action-less request.
Source
Thrown at v3/@claude-flow/security/src/policy/engine.ts:273
decision,
policyHash: policyHash({ mode: this.state.mode, rules: this.state.rules, budgets: this.state.budgets }),
};
const receiptId = policyHash(payloadWithoutId);
const payload = { receiptId, ...payloadWithoutId };
const hash = policyHash(payload);
const receipt: PolicyReceipt = {
payload,
hash,
signature: this.signingKey ? signPolicyHash(hash, this.signingKey) : undefined,
keyId: this.signingKey ? (this.keyId ?? 'local') : undefined,
};
this.state.receipts.push(receipt);
return receipt;
}
private validateRequest(request: PolicyRequest): void {
if (!request.identity?.id || !request.identity.type || !request.action?.type) {
throw new Error('invalid-policy-request');
}
for (const [name, value] of [
['costUsd', request.action.costUsd],
['tokens', request.action.tokens],
['concurrency', request.action.concurrency],
] as const) {
if (value !== undefined && (!Number.isFinite(value) || value < 0)) {
throw new Error(`invalid-policy-action-${name}`);
}
}
}
}
export function createLegacyCompatibleState(source = 'pre-ADR-324'): PolicyState {
return {
version: POLICY_STATE_VERSION,
mode: 'legacy',
migratedFrom: source,View on GitHub (pinned to fa13ee4ad6)
Solutions
- Always construct the full shape: { identity: { id, type }, action: { type, ... } } before evaluate().
- Add a type guard on the request at the adapter boundary and reject/log malformed ones there, where you still have context.
- Default identity.type explicitly (e.g. 'agent' or 'user') at the point the request is created.
Example fix
// before
const decision = engine.evaluate({ action: { type: 'tool.run' } } as PolicyRequest);
// after
const decision = engine.evaluate({
identity: { id: agent.id, type: 'agent' },
action: { type: 'tool.run', costUsd: 0.01 },
}); Defensive patterns
Strategy: type-guard
Validate before calling
if (!request?.identity?.id || !request.identity.type || !request.action?.type) {
throw new Error('policy request must set identity.id, identity.type, action.type');
}
const decision = engine.evaluate(request); Type guard
function isEvaluablePolicyRequest(r: unknown): r is PolicyRequest {
const req = r as PolicyRequest;
return typeof req?.identity?.id === 'string' && req.identity.id.length > 0
&& typeof req.identity.type === 'string' && req.identity.type.length > 0
&& typeof req?.action?.type === 'string' && req.action.type.length > 0;
} Try / catch
try {
return engine.evaluate(request);
} catch (err) {
if (err instanceof Error && err.message === 'invalid-policy-request') {
return deny('request missing identity or action'); // fail closed
}
throw err;
} Prevention
- Construct PolicyRequest in one factory that always sets identity and action types.
- Default identity.type ('agent' | 'user') where requests originate, not deep in adapters.
- Fail closed on malformed requests — treat evaluation errors as deny, not allow.
When it happens
Trigger: engine.evaluate({} as PolicyRequest); a request built from optional context where identity is undefined; mapping code that renames agentId -> id but leaves type unset; anonymized requests with the identity field stripped.
Common situations: Adapter layers dropping fields between the caller and the engine; new code paths that call evaluate before identity propagation is wired; tests calling evaluate with a bare action object.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- mode must be legacy, observe, or enforce
- approval issuance requires an authenticated human identity a
- policy-${decision.enforcedOutcome}:${decision.reason}; recei
- policy administration requires an authenticated user context
- worker policy denied: ${decision.reason ?? 'unknown reason'}
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/44f1298a2b890287.
Report an issue: GitHub.