swc-project/swc · error · TypeError

Property [Symbol.dispose] is not a function.

Error message

Property [Symbol.dispose] is not a function.

What it means

In `_using`, after the resource passes the object check, the helper resolves its disposal method via `value[Symbol.dispose]` (falling back to the `Symbol.for` polyfill key) and requires it to be callable. Otherwise it throws `TypeError: Property [Symbol.dispose] is not a function.`

Source

Thrown at crates/swc_ecma_transforms_base/src/helpers/generated/_using.rs:25

    local: "_using",
    import_path: "@swc/helpers/_/_using",
    #[cfg(feature = "inline-helpers")]
    source: r#"/* @minVersion 7.22.0 */

function _using(stack, value, isAwait) {
    if (value === null || value === void 0) return value;
    if (Object(value) !== value) {
        throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
    }
    // core-js-pure uses Symbol.for for polyfilling well-known symbols
    if (isAwait) {
        var dispose = value[Symbol.asyncDispose || Symbol.for("Symbol.asyncDispose")];
    }
    if (dispose === null || dispose === void 0) {
        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 });
    return value;
}
"#,
    #[cfg(feature = "inline-helpers")]
    deps: super::HelperBitmap::from_bits(0x00000010000000000000000000000000),
};

#[cfg(feature = "inline-helpers")]
pub fn stmts() -> &'static [swc_ecma_ast::Stmt] {
    static STMTS: once_cell::sync::Lazy<Vec<swc_ecma_ast::Stmt>> =
        once_cell::sync::Lazy::new(|| super::super::parse(DEF.source, DEF.import_path));
    &STMTS
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Give the resource a symbol-keyed method: `res[Symbol.dispose] = () => res.close();` before the `using` statement.
  2. Create an adapter object with `[Symbol.dispose]` that delegates to the library's close/release method.
  3. Verify disposability up front: `typeof res[Symbol.dispose] === 'function'`.
  4. On runtimes without `Symbol.dispose`, polyfill the symbol and attach methods under that same key.

Example fix

// before
using conn = await db.connect(); // only has conn.close()
// TypeError: Property [Symbol.dispose] is not a function.

// after
const conn = await db.connect();
using guarded = Object.create(conn, { [Symbol.dispose]: { value: () => conn.close() } });
// or: conn[Symbol.dispose] ??= () => conn.close(); using guarded = conn;
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm a callable dispose (or asyncDispose) before the using block.
const hasDisposeMethod = (v) => {
  if (v == null) return true;
  const key = Symbol.dispose || Symbol.for('Symbol.dispose');
  return typeof v[key] === 'function';
};
if (!hasDisposeMethod(res)) res[Symbol.dispose] = () => res.close();

Type guard

const isDisposable = (v: unknown): v is Disposable =>
  v != null &&
  (typeof v === 'object' || typeof v === 'function') &&
  typeof (v as Disposable)[Symbol.dispose ?? Symbol.for('Symbol.dispose')] === 'function';

Prevention

When it happens

Trigger: `using x = someObject;` where `someObject` has no `[Symbol.dispose]` method, or where the property exists but is not callable (null, number, string-keyed `dispose` instead of the symbol key).

Common situations: Wrapping third-party resources (DB connections, file handles) that only have a `.close()`/`.dispose()` method; test stubs without the symbol method; assuming `await using`-style async methods satisfy sync `using`.

Related errors


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