microsoft/aspire · error · InvalidOperationException

The 'manual' node_modules mode is not supported by…

Error message

The 'manual' node_modules mode is not supported by generated Deno Dockerfiles because node_modules is excluded from the build context. Use the 'auto' mode or provide a custom Dockerfile.

What it means

Deno's "manual" node_modules mode relies on a node_modules directory that the generated Docker build deliberately excludes from the build context (via .dockerignore). The image therefore cannot contain the files Deno needs, so the library throws instead of producing a broken image.

Solutions

  1. Switch the node_modules mode to auto (or remove the explicit setting to use the default).
  2. Remove WithDenoNodeModules / the manual-mode configuration from the resource.
  3. Provide a custom Dockerfile that copies or creates node_modules yourself if manual mode is required.

Example fix

// before
.WithDeno(deno => deno.WithNodeModulesDir(DenoNodeModulesDirMode.Manual))
// after
.WithDeno(deno => deno.WithNodeModulesDir(DenoNodeModulesDirMode.Auto))
Defensive patterns

Strategy: validation

Validate before calling

// reject manual node_modules mode before generating a Deno Dockerfile
if (deno is { NodeModulesDirSet: true, NodeModulesDirMode: DenoNodeModulesDirMode.Manual })
{
    throw new InvalidOperationException("Use DenoNodeModulesDirMode.Auto for generated Deno Dockerfiles.");
}

Try / catch

try
{
    app.WithDeno(deno => deno.WithNodeModulesDir(DenoNodeModulesDirMode.Auto));
}
catch (InvalidOperationException ex) when (ex.Message.Contains("'manual' node_modules mode"))
{
    // switch to Auto or supply a custom Dockerfile
}

Prevention

When it happens

Trigger: Calling WithDeno(...) with an explicit node_modules configuration setting DenoNodeModulesDirMode.Manual (or setting the equivalent deno.json/vendor option so DenoCommandLineAnnotation has NodeModulesDirSet=true and mode Manual), then generating the Dockerfile.

Common situations: Migrating a local Deno project that used --node-modules-dir=manual into container publish; a deno.json vendoring setup copied from a non-containerized workflow.

Related errors


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

Appendix: source

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

            publishMode.Mode is JavaScriptPublishMode.StaticWebsite or JavaScriptPublishMode.NodeServer)
        {
            var publishMethod = publishMode.Mode == JavaScriptPublishMode.StaticWebsite
                ? nameof(PublishAsStaticWebsite)
                : nameof(PublishAsNodeServer);
            throw new InvalidOperationException($"Generated Deno Dockerfiles do not support {publishMethod}. Use AddJavaScriptApp(...).WithDeno() or provide a custom Dockerfile.");
        }

        if (resource.TryGetLastAnnotation<JavaScriptPackageManagerAnnotation>(out var packageManager) &&
            !string.Equals(packageManager.ExecutableName, "deno", StringComparison.Ordinal))
        {
            throw new InvalidOperationException($"Generated Deno Dockerfiles do not support alternate package manager '{packageManager.ExecutableName}'. Use WithDeno() or provide a custom Dockerfile.");
        }

        if (resource.TryGetLastAnnotation<DenoCommandLineAnnotation>(out var deno) &&
            deno.NodeModulesDirSet &&
            deno.NodeModulesDirMode == DenoNodeModulesDirMode.Manual)
        {
            throw new InvalidOperationException("The 'manual' node_modules mode is not supported by generated Deno Dockerfiles because node_modules is excluded from the build context. Use the 'auto' mode or provide a custom Dockerfile.");
        }

        if (deno is not null)
        {
            if (deno.RuntimeArgs.Any(argument =>
                argument == "--env-file" ||
                argument.StartsWith("--env-file=", StringComparison.Ordinal)))
            {
                throw new InvalidOperationException(
                    "Generated Deno Dockerfiles do not support '--env-file' because dotenv files can contain secrets that would be copied into the container image. Use Aspire environment variables or secret parameters, or provide a custom Dockerfile that handles the file securely.");
            }

            // The Docker build context is the app directory, so a path that is absolute or escapes the app
            // directory is never copied into the image and would break both `deno cache` and the entrypoint.
            ThrowIfPathEscapesDenoBuildContext(deno.ConfigFile, nameof(WithDenoConfig));
            ThrowIfPathEscapesDenoBuildContext(deno.ImportMap, nameof(WithDenoImportMap));
            ThrowIfPathEscapesDenoBuildContext(deno.Lock, nameof(WithDenoLock));
        }

View on GitHub (pinned to 25830f84bd)