swc-project/swc · error · ReferenceError

Duplicated methods (${element.key}) can't be decorated.

Error message

Duplicated methods (${element.key}) can't be decorated.

What it means

The napi `parseFileSync(path, opts)` function loads the JS/TS file from disk via SourceMap::load_file and unwraps it with .expect("failed to read program file"). Any I/O failure - missing path, permission denied, or content the loader cannot handle - becomes a Rust panic that napi-rs reports to JS as an exception with this message. Unlike parse errors, nothing is captured by the swc handler because the panic happens before parsing starts.

Source

Thrown at crates/swc_ecma_transforms_base/src/helpers/generated/_decorate.rs:56

}
function _coalesceGetterSetter(element, other) {
    if (element.descriptor.get !== undefined) other.descriptor.get = element.descriptor.get;
    else other.descriptor.set = element.descriptor.set;
}
function _coalesceClassElements(elements) {
    var newElements = [];
    var isSameElement = function isSameElement(other) {
        return other.kind === "method" && other.key === element.key && other.placement === element.placement;
    };

    for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        var other;

        if (element.kind === "method" && (other = newElements.find(isSameElement))) {
            if (_isDataDescriptor(element.descriptor) || _isDataDescriptor(other.descriptor)) {
                if (_hasDecorators(element) || _hasDecorators(other)) {
                    throw new ReferenceError("Duplicated methods (" + element.key + ") can't be decorated.");
                }
                other.descriptor = element.descriptor;
            } else {
                if (_hasDecorators(element)) {
                    if (_hasDecorators(other)) {
                        throw new ReferenceError("Decorators can't be placed on different accessors with for " + "the same property (" + element.key + ").");
                    }
                    other.decorators = element.decorators;
                }
                _coalesceGetterSetter(element, other);
            }
        } else {
            newElements.push(element);
        }
    }

    return newElements;
}

View on GitHub (pinned to 5176682b65)

Solutions

  1. Verify the path before calling: use fs.existsSync / fs.statSync and resolve it to an absolute path with path.resolve.
  2. Check file readability (fs.accessSync(p, fs.constants.R_OK)) and fix permissions if needed.
  3. Prefer the buffer-based parse API (parseSync with source text) when you already have the contents in memory, avoiding filesystem coupling entirely.
  4. Wrap the call in try/catch and surface the JS exception message - it contains the path context from the panic.

Example fix

// before: panics inside Rust when the file is missing
const out = parseFileSync('src/app.ts', opts);

// after: validate first, then call
const file = path.resolve('src/app.ts');
fs.accessSync(file, fs.constants.R_OK);
const out = parseFileSync(file, opts);
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';

function parseFileSyncSafe(relPath, opts) {
  const file = path.resolve(relPath); // cwd-independent
  const st = fs.statSync(file); // throws ENOENT/EACCES with a clear JS error
  if (!st.isFile()) throw new Error(`not a file: ${file}`);
  fs.accessSync(file, fs.constants.R_OK);
  return parseFileSync(file, opts);
}

Type guard

function isReadableFile(p: string): boolean {
  try {
    return fs.statSync(p).isFile();
  } catch {
    return false;
  }
}

Try / catch

try {
  result = parseFileSync(file, opts);
} catch (e) {
  if (/failed to read program file/.test(String(e?.message))) {
    throw new Error(`swc could not read ${file}: check the path and permissions`, { cause: e });
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling parseFileSync('src/foo.ts', opts) where the file does not exist, is a directory, has no read permission, or the path is relative to a different working directory than assumed (the Rust side resolves it from the process cwd).

Common situations: Bundlers or CLIs run from a different cwd so a relative path resolves wrong; globs that include deleted files; permission-restricted mount or Docker volume without read access; case-sensitive filesystem mismatches after cloning a repo from Windows.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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