Skip to content

resolveFileSync returns no result when the discovered tsconfig has an unresolvable extends (tsgo still resolves) #1185

Description

@webpro

Summary

When resolveFileSync (with tsconfig: 'auto', or an explicit tsconfig) discovers a tsconfig.json whose extends target cannot be resolved (e.g. a package that isn't installed), it returns TsconfigNotFound for every specifier from files under that config — including plain relative imports that don't depend on the tsconfig at all.

tsc / typescript-go instead treat an unresolvable extends as a non-fatal diagnostic (TS6053) and keep resolving modules, using the options that did parse.

This is separate from the recent extends-validity alignment (#1167, #1170): the extends here is correctly classified as not-found — the question is what module resolution does afterwards. It's also adjacent to #1011 (surfacing the loaded configs on error).

Reproduction

.
├── tsconfig.json
├── a.ts
├── b.ts
└── src/x.ts
// tsconfig.json — extends a package that is NOT installed
{
  "extends": "@acme/base/tsconfig.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@app/*": ["./src/*"] }
  }
}
// a.ts
import { b } from './b';     // relative — does not depend on the tsconfig
import { x } from '@app/x';  // alias — uses local compilerOptions.paths

// b.ts
export const b = 1;
// src/x.ts
export const x = 1;
// repro.mjs   (npm i oxc-resolver)
import { ResolverFactory } from 'oxc-resolver';
const base = new URL('./a.ts', import.meta.url).pathname;
const opts = { extensions: ['.ts', '.tsx', '.js', '.d.ts'] };
const auto = new ResolverFactory({ tsconfig: 'auto', ...opts });
const plain = new ResolverFactory(opts);
for (const spec of ['./b', '@app/x']) {
  const r = auto.resolveFileSync(base, spec);
  console.log(`auto ${spec} ->`, r.path ?? r.error);
}
console.log('no tsconfig ./b ->', plain.resolveFileSync(base, './b').path);

Actual (oxc-resolver 11.20.0)

tsconfig:'auto'  ./b      -> ERROR: "Tsconfig not found @acme/base/tsconfig.json"
tsconfig:'auto'  @app/x   -> ERROR: "Tsconfig not found @acme/base/tsconfig.json"
no tsconfig      ./b      -> .../b.ts

The same TsconfigNotFound occurs with an explicit tsconfig: { configFile: '.../tsconfig.json' }, so it isn't 'auto'-specific.

Expected (matches tsc / typescript-go)

tsgo --traceResolution on the same project:

======== Module name './b' was successfully resolved to '.../b.ts'. ========
======== Module name '@app/x' was successfully resolved to '.../src/x.ts'. ========
tsconfig.json(2,14): error TS6053: File '@acme/base/tsconfig.json' not found.

Both the relative import and the path alias resolve (the latter via the local paths), and the unresolvable extends surfaces as a separate, non-fatal diagnostic — not as a failure of all resolution. At minimum, a relative import should never fail because of an unrelated tsconfig load error.

Impact

Any consumer using tsconfig: 'auto' over a workspace loses all resolution for files under a tsconfig that extends a package which isn't installed (common in monorepos, or before/while dependencies are installed). Downstream (knip) this currently requires a second, tsconfig-less fallback resolver to recover.

Environment

  • oxc-resolver 11.20.0
  • Node.js 24
  • macOS (arm64)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions