{"record":{"id":"26e0e442215da821","repo":"ruvnet/ruflo","slug":"unknown-permissions-preset-name-valid-presets","errorCode":null,"errorMessage":"Unknown permissions preset: ${name}. Valid presets: ${valid}","messagePattern":"Unknown permissions preset: (.+?)\\. Valid presets: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/permission/permission-set.ts","lineNumber":138,"sourceCode":"      deniedTools: [],\n      allowedPaths: ['**/*'],\n      deniedPaths: [],\n      allowedNetworkHosts: ['*'],\n      notes: 'No restriction. Kept for opt-in compatibility; see #2768 for why this is not the default.',\n    },\n  ],\n};\n\nexport type PresetName = keyof typeof PRESETS;\n\n/**\n * Resolve a preset name to its per-role sets. Throws on unknown preset —\n * fail loud so a typo doesn't silently degrade to permissive.\n */\nexport function resolvePreset(name: string): PermissionSet[] {\n  if (!(name in PRESETS)) {\n    const valid = Object.keys(PRESETS).join(', ');\n    throw new Error(`Unknown permissions preset: ${name}. Valid presets: ${valid}`);\n  }\n  return PRESETS[name as PresetName];\n}\n\n/**\n * Sanity-check a permission set: role name shape, no null entries.\n * Path validation is deferred to the enforcement side (PathValidator)\n * so this module has no @claude-flow/security runtime dep beyond a\n * type-only import.\n */\nexport function validatePermissionSet(set: PermissionSet, _validator?: PathValidator): string[] {\n  const errors: string[] = [];\n  if (!set.role || typeof set.role !== 'string') errors.push('role must be a non-empty string');\n  const arrays: [keyof PermissionSet, unknown][] = [\n    ['allowedTools', set.allowedTools],\n    ['deniedTools', set.deniedTools],\n    ['allowedPaths', set.allowedPaths],\n    ['deniedPaths', set.deniedPaths],","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/permission/permission-set.ts#L120-L156","documentation":"resolvePreset(name) in permission-set.ts looks the name up in the PRESETS map, which defines exactly three presets: 'strict', 'standard', 'permissive'. An unknown name throws with the valid list appended. The throw is deliberate — fail loud so a typo in configuration cannot silently degrade to a permissive permission set.","triggerScenarios":"Loading a config that sets the permissions preset to anything besides strict|standard|permissive — e.g. 'default', 'safe', 'locked', 'read-only', 'Standard' (case-sensitive), or a preset name from an older/newer version that was renamed or removed.","commonSituations":"Config files written against different documentation than the installed version; CI configs with a typo; downstream tools guessing preset names; presets renamed between releases leaving stale configs.","solutions":["Set the preset to one of the three valid names: 'strict', 'standard', or 'permissive' (exact, lowercase).","Check for typos and case — the lookup is a plain object-key check, so 'Standard' fails.","If upgrading, diff your config against the PRESETS keys in the installed src/permission/permission-set.ts.","If you truly need a custom set, build PermissionSet objects explicitly instead of relying on a preset name."],"exampleFix":"// before\n{ permissions: { preset: 'safe' } } // throws: Unknown permissions preset: safe. Valid presets: strict, standard, permissive\n\n// after\n{ permissions: { preset: 'strict' } }","handlingStrategy":"type-guard","validationCode":"const VALID_PRESETS = ['strict', 'standard', 'permissive'] as const;\nfunction assertPreset(name: string): void {\n  if (!VALID_PRESETS.includes(name as any)) {\n    throw new Error(`Unknown permissions preset: ${name}. Valid presets: ${VALID_PRESETS.join(', ')}`);\n}\n// Run this on config load, before resolvePreset is ever reached.","typeGuard":"type PresetName = 'strict' | 'standard' | 'permissive';\nconst PRESET_NAMES: ReadonlySet<string> = new Set(['strict', 'standard', 'permissive']);\nfunction isPresetName(name: unknown): name is PresetName {\n  return typeof name === 'string' && PRESET_NAMES.has(name);\n}","tryCatchPattern":"try {\n  const sets = resolvePreset(config.permissions.preset);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Unknown permissions preset:')) {\n    failConfigStartup(e.message); // refuse to boot — never substitute a default preset silently\n  }\n  throw e;\n}","preventionTips":["Validate preset names at config load with the exact three-value list; treat anything else as a startup error.","Add a JSON-schema enum for the preset field if configs are machine-generated.","After upgrading @claude-flow/cli, re-check the PRESETS keys in permission-set.ts before shipping old configs."],"tags":["permissions","config","preset","validation"],"backgroundTag":"invalid-config-value","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}