oxc-project/oxc · warning · OxcDiagnostic

Ambient modules cannot be nested in other modules or namespa

Error message

Ambient modules cannot be nested in other modules or namespaces.

What it means

Oxc's TypeScript namespace transform reports this when a module-string declaration (`declare module "..." {}` / TSExternalModuleDeclaration) is encountered where it is only legal at top level but appears nested inside a namespace body being flattened. During `handle_nested` (crates/oxc_transformer/src/typescript/namespace.rs:119-286), any `Declaration::TSExternalModuleDeclaration` found in the namespace body is routed to `handle_external` (namespace.rs:266-268), which errors when the declaration is not marked `declare` (namespace.rs:112-115). It mirrors TypeScript's TS2664 'Ambient modules cannot be nested in other modules or namespaces'.

Source

Thrown at crates/oxc_transformer/src/typescript/diagnostics.rs:25

        .with_help(
            "Consider using 'import * as ns from \"mod\"',
         'import {a} from \"mod\"', 'import d from \"mod\"', or another module format instead.",
        )
        .with_label(span)
        .with_error_code("TS", "1202")
}

#[cold]
pub fn export_assignment_cannot_bed_used_in_esm(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Export assignment cannot be used when targeting ECMAScript modules.")
        .with_help("Consider using 'export default' or another module format instead.")
        .with_label(span)
        .with_error_code("TS", "1203")
}

#[cold]
pub fn ambient_module_nested(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Ambient modules cannot be nested in other modules or namespaces.")
        .with_label(span)
}

#[cold]
pub fn namespace_exporting_non_const(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Namespaces exporting non-const are not supported by Oxc. Change to const or see: https://oxc.rs/docs/guide/usage/transformer/typescript.html#partial-namespace-support")
        .with_label(span)
}

#[cold]
pub fn namespace_not_supported(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Namespace not marked type-only declare are disabled. To enable and review caveats see: https://oxc.rs/docs/guide/usage/transformer/typescript.html#partial-namespace-support")
        .with_label(span)
}

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Move the `declare module "..." { ... }` block out to the top level of the file
  2. Ensure the nested declaration is truly ambient by marking it `declare module "..."` (declarations with `declare` do not trip the check in handle_external)
  3. If the nesting was accidental (bad merge or copy-paste), delete the stray inner module declaration
  4. For augmentation inside namespaces, split the file: keep the namespace in one file and the module augmentation at top level of another

Example fix

// before
namespace Config {
  declare module "json-schema" {
    interface Schema { id: string }
  }
}

// after
namespace Config { /* ... */ }

declare module "json-schema" {
  interface Schema { id: string }
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject nested ambient modules before transform (grounded: fires only for non-declare nested TSExternalModuleDeclaration)
function hasNestedAmbientModule(src: string): boolean {
  // heuristic: a `declare module "..."`/`module "..."` block indented inside namespace/module braces
  return /(?:^|\n)\s{2,}(declare\s+)?module\s+["'][^"']+["']\s*\{/.test(src);
}

Type guard

// For programmatically built .d.ts content, validate structure before writing
function isValidAugmentationPlacement(decl: { kind: 'module'; parent: string | null; hasDeclare: boolean }) {
  if (decl.kind === 'module' && decl.parent !== null && !decl.hasDeclare) {
    throw new Error('ambient module declarations must be top-level (TS2664)');
  }
  return true;
}

Prevention

When it happens

Trigger: Transforming TypeScript where a `module "name" { ... }` / `declare module "name"` block sits inside `namespace Foo { ... }` or `module Foo { ... }` while namespaces are enabled (`allowNamespaces: true`, the default), and the nested external-module declaration lacks the `declare` modifier. Also fires for a top-level non-`declare` TSExternalModuleDeclaration passing through `enter_program`'s handle_external call (namespace.rs:47-52).

Common situations: Hand-written ambient typings pasted inside utility namespaces; refactoring a `.d.ts` that declared module augmentations (`declare module "lib"`) into a wrapped namespace for organization; generated typings from older tooling that nested module declarations; merging several declaration files where an `export declare module` ended up inside a wrapping namespace.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/120bf821ac58e871. Report an issue: GitHub.