{"record":{"id":"44f1298a2b890287","repo":"ruvnet/ruflo","slug":"invalid-policy-request","errorCode":null,"errorMessage":"invalid-policy-request","messagePattern":"invalid-policy-request","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/security/src/policy/engine.ts","lineNumber":273,"sourceCode":"      decision,\n      policyHash: policyHash({ mode: this.state.mode, rules: this.state.rules, budgets: this.state.budgets }),\n    };\n    const receiptId = policyHash(payloadWithoutId);\n    const payload = { receiptId, ...payloadWithoutId };\n    const hash = policyHash(payload);\n    const receipt: PolicyReceipt = {\n      payload,\n      hash,\n      signature: this.signingKey ? signPolicyHash(hash, this.signingKey) : undefined,\n      keyId: this.signingKey ? (this.keyId ?? 'local') : undefined,\n    };\n    this.state.receipts.push(receipt);\n    return receipt;\n  }\n\n  private validateRequest(request: PolicyRequest): void {\n    if (!request.identity?.id || !request.identity.type || !request.action?.type) {\n      throw new Error('invalid-policy-request');\n    }\n    for (const [name, value] of [\n      ['costUsd', request.action.costUsd],\n      ['tokens', request.action.tokens],\n      ['concurrency', request.action.concurrency],\n    ] as const) {\n      if (value !== undefined && (!Number.isFinite(value) || value < 0)) {\n        throw new Error(`invalid-policy-action-${name}`);\n      }\n    }\n  }\n}\n\nexport function createLegacyCompatibleState(source = 'pre-ADR-324'): PolicyState {\n  return {\n    version: POLICY_STATE_VERSION,\n    mode: 'legacy',\n    migratedFrom: source,","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/security/src/policy/engine.ts#L255-L291","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nconst decision = engine.evaluate({ action: { type: 'tool.run' } } as PolicyRequest);\n\n// after\nconst decision = engine.evaluate({\n  identity: { id: agent.id, type: 'agent' },\n  action: { type: 'tool.run', costUsd: 0.01 },\n});","handlingStrategy":"type-guard","validationCode":"if (!request?.identity?.id || !request.identity.type || !request.action?.type) {\n  throw new Error('policy request must set identity.id, identity.type, action.type');\n}\nconst decision = engine.evaluate(request);","typeGuard":"function isEvaluablePolicyRequest(r: unknown): r is PolicyRequest {\n  const req = r as PolicyRequest;\n  return typeof req?.identity?.id === 'string' && req.identity.id.length > 0\n    && typeof req.identity.type === 'string' && req.identity.type.length > 0\n    && typeof req?.action?.type === 'string' && req.action.type.length > 0;\n}","tryCatchPattern":"try {\n  return engine.evaluate(request);\n} catch (err) {\n  if (err instanceof Error && err.message === 'invalid-policy-request') {\n    return deny('request missing identity or action'); // fail closed\n  }\n  throw err;\n}","preventionTips":["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."],"tags":["policy","validation","authorization"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}