swc-project/swc · error · TypeError

using declarations can only be used with objects, functions,

Error message

using declarations can only be used with objects, functions, null, or undefined.

What it means

This TypeError is thrown at runtime by the _using_ctx helper that SWC injects when lowering `using` / `await using` declarations (explicit resource management) for targets without native support. The helper's using() function validates every bound value with `Object(value) !== value`, rejecting primitives before looking for a dispose method. The error therefore appears when the compiled output executes, not during the SWC transform itself.

Source

Thrown at crates/swc_ecma_transforms_base/src/helpers/mod.rs:624

            Default::default(),
            |_| {
                enable_helper!(using_ctx);
                inject_helpers(Mark::new())
            },
            "let _throw = null",
            r#"
            function _using_ctx() {
                var _disposeSuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed) {
                    var err = new Error();
                    err.name = "SuppressedError";
                    err.suppressed = suppressed;
                    err.error = error;
                    return err;
                }, empty = {}, stack = [];
                function using(isAwait, value) {
                    if (value != null) {
                        if (Object(value) !== value) {
                            throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
                        }
                        if (isAwait) {
                            var dispose = value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")];
                        }
                        if (dispose == null) {
                            dispose = value[Symbol.dispose || Symbol.for("Symbol.dispose")];
                        }
                        if (typeof dispose !== "function") {
                            throw new TypeError(`Property [Symbol.dispose] is not a function.`);
                        }
                        stack.push({
                            v: value,
                            d: dispose,
                            a: isAwait
                        });
                    } else if (isAwait) {
                        stack.push({
                            d: value,

View on GitHub (pinned to 5176682b65)

Solutions

  1. Make the bound value an object or function that implements [Symbol.dispose] (and/or [Symbol.asyncDispose] for `await using`) — have the producer return that wrapper instead of the primitive
  2. Narrow before binding: only reach the `using` declaration when the value is an object, function, null, or undefined (null/undefined are legal no-ops for the helper)
  3. Wrap primitives explicitly: `using guard = { [Symbol.dispose]() { release(handleId); } }`
  4. Target a runtime with native `using` support (Node 20+/recent targets) so SWC emits the native syntax instead of the validating helper

Example fix

// before
using token = acquireToken(); // acquireToken() returns a number -> helper throws

// after
const token = acquireToken();
using guard = { [Symbol.dispose]() { releaseToken(token); } };
Defensive patterns

Strategy: validation

Validate before calling

// Run before executing code whose `using` bindings come from external APIs.
function assertUsableUsingValue(value) {
  if (value != null && Object(value) !== value) {
    throw new TypeError(
      `Invalid using value: expected object/function/null/undefined, got ${typeof value}`
    );
  }
}

Type guard

type UsingValue = object | ((...args: unknown[]) => unknown) | null | undefined;
function isUsingValue(v: unknown): v is UsingValue {
  return v == null || typeof v === 'object' || typeof v === 'function';
}

Try / catch

try {
  using res = acquire(); // compiled to the _using_ctx helper
} catch (e) {
  if (e instanceof TypeError && /using declarations can only be used with objects/.test(e.message)) {
    // producer returned a primitive — fix the producer, do not retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Compiling `using x = 42`, `using x = 'str'`, or `await using x = true` (also symbol/bigint) with @swc/core so the helper runs on execution; an API that is statically typed as an object but actually returns a number/string at runtime and is bound with `using`.

Common situations: Refactoring try/finally cleanup into `using` where the acquired value is a handle/ID number; test code binding dummy primitive literals; union-typed producers (e.g. number | Connection) consumed directly by `using`.

Related errors


AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17). Data as JSON: /api/errors/209d109b42010d6e. Report an issue: GitHub.