{"record":{"id":"04d2d858a711a3bd","repo":"ruvnet/ruflo","slug":"piipolicy-must-be-one-of-pii-policies-join","errorCode":null,"errorMessage":"piiPolicy must be one of: ${PII_POLICIES.join(', ')}","messagePattern":"piiPolicy must be one of: (.+?)","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":222,"sourceCode":"  if (agents.length === 0) {\n    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');\n  }\n  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {\n    if (typeof t !== 'string' || t.length === 0) {\n      throw new PodTemplateValidationError(\n        'allowedMcpTools entries must be non-empty strings',\n        tp,\n      );\n    }\n    return t;\n  });\n  if (allowedMcpTools.length === 0) {\n    throw new PodTemplateValidationError('allowedMcpTools must have ≥1 entry', '/');\n  }\n  const bench = validatePodBench(json.bench, '/bench');\n  const piiPolicy = requireString(json, 'piiPolicy', '/');\n  if (!PII_POLICIES.includes(piiPolicy as PiiPolicy)) {\n    throw new PodTemplateValidationError(\n      `piiPolicy must be one of: ${PII_POLICIES.join(', ')}`,\n      '/',\n    );\n  }\n  const budgetUsdMonthly = requireNumber(json, 'budgetUsdMonthly', '/');\n  if (budgetUsdMonthly < 0) {\n    throw new PodTemplateValidationError('budgetUsdMonthly must be ≥0', '/');\n  }\n  const budgetUsdPerRun = requireNumber(json, 'budgetUsdPerRun', '/');\n  if (budgetUsdPerRun < 0) {\n    throw new PodTemplateValidationError('budgetUsdPerRun must be ≥0', '/');\n  }\n  if (budgetUsdMonthly > 0 && budgetUsdPerRun > budgetUsdMonthly) {\n    throw new PodTemplateValidationError(\n      'budgetUsdPerRun must not exceed budgetUsdMonthly',\n      '/',\n    );\n  }","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L204-L240","documentation":"The top-level piiPolicy string must be one of the closed set defined in PII_POLICIES: 'soc2', 'gdpr', 'hipaa', 'permissive' (the ${PII_POLICIES.join(', ')} in the message is interpolated at throw time to exactly that list). Any other value — including case variants like 'SOC2' — is rejected at path '/'.","triggerScenarios":"A template with piiPolicy set to \"SOC2\", \"GDPR\", \"none\", \"strict\", \"eu-gdpr\", or a typo like \"sox2\". requireString already guaranteed it is a string, so the failure is purely an unrecognized enum value.","commonSituations":"Uppercase policy names copied from compliance docs; 'none'/'strict' guesses by authors who never saw the enum; regional aliases ('eu-gdpr') from internal config systems.","solutions":["Set piiPolicy to exactly one of: soc2, gdpr, hipaa, permissive (lowercase)","If unsure which applies, 'permissive' is the least restrictive valid value — confirm with your compliance requirements","Guard in your template generator with an allowed-set check so invalid values never reach validation"],"exampleFix":"// before\n\"piiPolicy\": \"SOC2\"\n// after\n\"piiPolicy\": \"soc2\"","handlingStrategy":"validation","validationCode":"const PII = ['soc2', 'gdpr', 'hipaa', 'permissive'] as const;\nif (!PII.includes(template.piiPolicy)) template.piiPolicy = 'permissive'; // or reject explicitly","typeGuard":"const PII_POLICIES = ['soc2', 'gdpr', 'hipaa', 'permissive'] as const;\nfunction isPiiPolicy(v: unknown): v is typeof PII_POLICIES[number] {\n  return typeof v === 'string' && (PII_POLICIES as readonly string[]).includes(v);\n}","tryCatchPattern":"try { validatePodTemplate(json); } catch (err) {\n  if (err instanceof PodTemplateValidationError && /piiPolicy/.test(err.message)) {\n    // message lists the exact allowed values — lowercase and retry\n  }\n}","preventionTips":["Lowercase policy names at the config boundary","Keep the enum in one shared constant instead of re-typing it in templates"],"tags":["schema-validation","business-pods","pii","compliance","enum","configuration"],"backgroundTag":"invalid-enum-value","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"}