{"record":{"id":"5cf264fcd982f2b8","repo":"microsoft/aspire","slug":"the-permission-kind-must-be-a-defined-denopermissionkind","errorCode":null,"errorMessage":"The permission kind must be a defined DenoPermissionKind value.","messagePattern":"The permission kind must be a defined DenoPermissionKind value\\.","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.JavaScript/DenoHostingExtensions.cs","lineNumber":48,"sourceCode":"        if (!builder.Resource.TryGetLastAnnotation<DenoCommandLineAnnotation>(out var annotation))\n        {\n            annotation = new DenoCommandLineAnnotation();\n            builder.WithAnnotation(annotation);\n        }\n\n        return annotation;\n    }\n\n    private static IResourceBuilder<DenoAppResource> AddDenoPermission(\n        IResourceBuilder<DenoAppResource> builder,\n        DenoPermissionKind kind,\n        bool deny,\n        string[] values)\n    {\n        ArgumentNullException.ThrowIfNull(builder);\n        if (!Enum.IsDefined(kind))\n        {\n            throw new ArgumentOutOfRangeException(nameof(kind), kind, \"The permission kind must be a defined DenoPermissionKind value.\");\n        }\n\n        // The caller owns the params array and can keep mutating it after this call. Permissions are only read\n        // when the command line is materialized (publish, or resource start), so holding the caller's array by\n        // reference would let a later mutation silently rewrite the launch arguments. Snapshot it, matching the\n        // copy semantics WithDenoScriptArgs and WithDenoRuntimeArgs already get from AddRange.\n        string[] snapshot = values is null ? [] : [.. values];\n        var permission = new DenoPermission\n        {\n            Kind = kind,\n            Deny = deny,\n            Values = snapshot,\n        };\n\n        // Deno delimits permission values with commas and offers no escape syntax, so a single value containing a\n        // comma silently becomes several permissions. Verified on Deno 2.9.0: `--allow-read=data,secret` intended as\n        // one directory named \"data,secret\" instead grants `data` and `secret` separately, so the requested path is\n        // denied while unrelated paths are granted. Reject it here rather than emit a command line that means","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.JavaScript/DenoHostingExtensions.cs#L30-L66","documentation":"AddDenoPermission validates that the DenoPermissionKind argument is a defined enum member before building the --allow/--deny flag. An undefined value (bad cast, new member from a newer assembly) would otherwise emit a malformed Deno CLI flag, so it throws ArgumentOutOfRangeException.","triggerScenarios":"Calling WithDenoAllow/WithDenoDeny with a kind value obtained by casting an int/string that is not a defined DenoPermissionKind, or from a mismatched assembly version with different enum values.","commonSituations":"Parsing permission kinds from JSON/YAML config and casting directly; binary incompatibility after enum changes; hand-rolled helper methods constructing the enum.","solutions":["Use the named DenoPermissionKind constants (e.g. DenoPermissionKind.Read) instead of casts.","Validate with Enum.IsDefined before converting config input to the enum.","Rebuild against the same Aspire.Hosting.JavaScript version you run with.","If adding a new DenoPermissionKind member, the library (not user code) must be updated."],"exampleFix":"// before\nvar kind = (DenoPermissionKind)Enum.Parse(typeof(DenoPermissionKind), configValue, ignoreCase: true);\nresource.WithDenoAllow(kind);\n// after\nif (!Enum.TryParse<DenoPermissionKind>(configValue, ignoreCase: true, out var kind) || !Enum.IsDefined(kind))\n    throw new ArgumentException($\"Unknown Deno permission kind '{configValue}'.\");\nresource.WithDenoAllow(kind);","handlingStrategy":"validation","validationCode":"if (!Enum.IsDefined(typeof(DenoPermissionKind), kind)) throw new ArgumentException(\"kind must be a defined DenoPermissionKind\");","typeGuard":"static bool IsDefinedPermission(DenoPermissionKind k) => Enum.IsDefined(k);","tryCatchPattern":"try { resource.WithDenoAllow(kind, values); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"kind\") { /* surface as config error */ }","preventionTips":["Prefer Enum.TryParse + Enum.IsDefined over direct casts","Use constants, not magic numbers, for enum arguments","Pin Aspire package versions so enum definitions match"],"tags":["argument-exception","enum","deno","validation"],"backgroundTag":"invalid-enum-argument","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}