microsoft/aspire · error · ArgumentOutOfRangeException

The permission kind must be a defined DenoPermissionKind…

Error message

The permission kind must be a defined DenoPermissionKind value.

What it means

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.

Solutions

  1. Use the named DenoPermissionKind constants (e.g. DenoPermissionKind.Read) instead of casts.
  2. Validate with Enum.IsDefined before converting config input to the enum.
  3. Rebuild against the same Aspire.Hosting.JavaScript version you run with.
  4. If adding a new DenoPermissionKind member, the library (not user code) must be updated.

Example fix

// before
var kind = (DenoPermissionKind)Enum.Parse(typeof(DenoPermissionKind), configValue, ignoreCase: true);
resource.WithDenoAllow(kind);
// after
if (!Enum.TryParse<DenoPermissionKind>(configValue, ignoreCase: true, out var kind) || !Enum.IsDefined(kind))
    throw new ArgumentException($"Unknown Deno permission kind '{configValue}'.");
resource.WithDenoAllow(kind);
Defensive patterns

Strategy: validation

Validate before calling

if (!Enum.IsDefined(typeof(DenoPermissionKind), kind)) throw new ArgumentException("kind must be a defined DenoPermissionKind");

Type guard

static bool IsDefinedPermission(DenoPermissionKind k) => Enum.IsDefined(k);

Try / catch

try { resource.WithDenoAllow(kind, values); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "kind") { /* surface as config error */ }

Prevention

When it happens

Trigger: 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.

Common situations: Parsing permission kinds from JSON/YAML config and casting directly; binary incompatibility after enum changes; hand-rolled helper methods constructing the enum.

Understand the failure class

Background: "invalid argument", "unknown mode", "not supported": invalid enum-like argument errors explained — this error's family across 19 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/5cf264fcd982f2b8. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.JavaScript/DenoHostingExtensions.cs:48

        if (!builder.Resource.TryGetLastAnnotation<DenoCommandLineAnnotation>(out var annotation))
        {
            annotation = new DenoCommandLineAnnotation();
            builder.WithAnnotation(annotation);
        }

        return annotation;
    }

    private static IResourceBuilder<DenoAppResource> AddDenoPermission(
        IResourceBuilder<DenoAppResource> builder,
        DenoPermissionKind kind,
        bool deny,
        string[] values)
    {
        ArgumentNullException.ThrowIfNull(builder);
        if (!Enum.IsDefined(kind))
        {
            throw new ArgumentOutOfRangeException(nameof(kind), kind, "The permission kind must be a defined DenoPermissionKind value.");
        }

        // The caller owns the params array and can keep mutating it after this call. Permissions are only read
        // when the command line is materialized (publish, or resource start), so holding the caller's array by
        // reference would let a later mutation silently rewrite the launch arguments. Snapshot it, matching the
        // copy semantics WithDenoScriptArgs and WithDenoRuntimeArgs already get from AddRange.
        string[] snapshot = values is null ? [] : [.. values];
        var permission = new DenoPermission
        {
            Kind = kind,
            Deny = deny,
            Values = snapshot,
        };

        // Deno delimits permission values with commas and offers no escape syntax, so a single value containing a
        // comma silently becomes several permissions. Verified on Deno 2.9.0: `--allow-read=data,secret` intended as
        // one directory named "data,secret" instead grants `data` and `secret` separately, so the requested path is
        // denied while unrelated paths are granted. Reject it here rather than emit a command line that means

View on GitHub (pinned to 25830f84bd)