{"record":{"id":"f70a6c250f66a390","repo":"ruvnet/ruflo","slug":"invalid-policy-action-name","errorCode":null,"errorMessage":"invalid-policy-action-${name}","messagePattern":"invalid-policy-action-(.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/security/src/policy/engine.ts","lineNumber":281,"sourceCode":"      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,\n    migratedAt: Date.now(),\n    rules: [],\n    budgets: [],\n    usage: [],\n    approvals: [],\n    receipts: [],\n  };\n}","sourceCodeStart":263,"sourceCodeEnd":299,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/security/src/policy/engine.ts#L263-L299","documentation":"validateRequest() also checks the numeric action metrics: costUsd, tokens, and concurrency, when present, must be finite and non-negative — otherwise it throws Error(`invalid-policy-action-${name}`) with name substituted (invalid-policy-action-costUsd, -tokens, or -concurrency). The literal template string in the message identifies which metric is bad.","triggerScenarios":"action.costUsd: -0.5 from refund/credit arithmetic; tokens: NaN after summing telemetry that contains undefined; concurrency: Infinity from a division meant to compute parallelism.","commonSituations":"Aggregating usage numbers where one source returns undefined (sum becomes NaN); sign errors in cost accounting; passing raw provider payloads whose numeric fields are sometimes strings or missing.","solutions":["Inspect the error message suffix to identify the offending metric, then fix that field's producer.","Sanitize metrics before evaluation: omit the field when not finite/non-negative, or clamp to 0.","Type the telemetry aggregation so undefined entries default to 0 instead of poisoning sums with NaN."],"exampleFix":"// before\nengine.evaluate({ identity, action: { type: 'llm.call', tokens: undefined as any, costUsd: total } });\n// total is NaN when inputs missing -> invalid-policy-action-costUsd\n\n// after\nconst costUsd = Number.isFinite(total) && total >= 0 ? total : 0;\nengine.evaluate({ identity, action: { type: 'llm.call', costUsd } });","handlingStrategy":"validation","validationCode":"function metric(v: number | undefined): number | undefined {\n  if (v === undefined) return undefined;\n  return Number.isFinite(v) && v >= 0 ? v : undefined;\n}\nengine.evaluate({\n  identity,\n  action: {\n    type: 'llm.call',\n    costUsd: metric(totalCost),\n    tokens: metric(totalTokens),\n    concurrency: metric(inFlight),\n  },\n});","typeGuard":"function isNonNegativeFinite(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":"try {\n  return engine.evaluate(request);\n} catch (err) {\n  if (err instanceof Error && /^invalid-policy-action-(costUsd|tokens|concurrency)$/.test(err.message)) {\n    const field = err.message.replace('invalid-policy-action-', '');\n    logger.warn(`dropping bad metric ${field}=${(request.action as any)[field]}`);\n    return engine.evaluate({ ...request, action: { ...request.action, [field]: undefined } });\n  }\n  throw err;\n}","preventionTips":["Sum telemetry with an explicit numeric default ((acc, v) => acc + (v ?? 0)) so undefined never poisons totals.","Check metric names in the thrown suffix to pinpoint the field to sanitize.","Unit-test evaluate() inputs with NaN, Infinity, and negative values for each metric."],"tags":["policy","numbers","validation"],"backgroundTag":"invalid-metric-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}