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

  1. Always construct the full shape: { identity: { id, type }, action: { type, ... } } before evaluate().
  2. Add a type guard on the request at the adapter boundary and reject/log malformed ones there, where you still have context.
  3. 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

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


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/44f1298a2b890287. Report an issue: GitHub.