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
- 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
- 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)
- Wrap primitives explicitly: `using guard = { [Symbol.dispose]() { release(handleId); } }`
- 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
- Type resources as interfaces with [Symbol.dispose] so TypeScript rejects primitives at compile time
- Never bind primitive handles/IDs directly — wrap them in a disposable object at the API boundary
- Execute the transformed output in tests, not just the SWC transform, so helper runtime errors surface in CI
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
- Property [Symbol.dispose] is not a function.
- Object expected.
- Symbol.dispose is not defined.
- Object not disposable.
- using declarations can only be used with objects, functions,
AI-assisted analysis of swc-project/swc@5176682b65 (2026-08-17).
Data as JSON: /api/errors/209d109b42010d6e.
Report an issue: GitHub.