Skip to content

Debug Symbol Resolution Issues

import { Aside, Tabs, TabItem } from ‘@astrojs/starlight/components’;

Symbol resolution issues appear as broken imports in forge health, missing results from forge_search_symbols, or forge_trace_imports returning empty when you know imports exist. This guide walks through the diagnostic tools and the common causes.

Before diagnosing why a symbol can’t be found, confirm it was extracted at all.

Use forge_parse_file (MCP) or forge stats (CLI) to inspect what Forge sees in a specific file.

Via MCP:

Call forge_parse_file on src/lib/payments.ts

Expected output:

forge_parse_file: src/lib/payments.ts
Exports:
- createPayment (function, line 12)
- PaymentConfig (interface, line 3)
- PaymentResult (type alias, line 8)
- DEFAULT_CURRENCY (const, line 1)
Imports:
- ../models/cart (CartItem, CartTotal) → resolved: src/models/cart.ts
- ../config/env (ENV) → resolved: src/config/env.ts
- stripe (Stripe) → resolved: node_modules/stripe (external, not indexed)
Symbol count: 4 exports, 3 imports

If the symbol you’re looking for is NOT in the exports list, Forge never extracted it. This could mean:

  • The file has a syntax error that prevented parsing
  • The export uses an unusual syntax Forge doesn’t recognize
  • The file is in an ignored_paths directory

Broken imports appear in forge health as P0 findings. To inspect why a specific import doesn’t resolve, use forge_trace_imports:

Via MCP:

Call forge_trace_imports on src/api/orders.ts

Expected output for a working file:

forge_trace_imports: src/api/orders.ts
Direct imports (4):
../lib/payments → RESOLVED → src/lib/payments.ts
../models/order → RESOLVED → src/models/order.ts
../utils/validate → RESOLVED → src/utils/validate.ts
@stripe/stripe-js → EXTERNAL (not indexed)

A broken import looks like:

../lib/stripe-client → UNRESOLVED
Attempted paths:
src/lib/stripe-client.ts — not found
src/lib/stripe-client/index.ts — not found
src/lib/stripe-client.js — not found

“Not found” means the file doesn’t exist at that path. Either the import is wrong, the file was moved, or there’s a path alias that Forge doesn’t know about.

Path aliases are a common source of broken imports. If your TypeScript project uses @app/*, @shared/*, or ~/*, Forge needs to know how to resolve them.

First, check if Forge already reads your tsconfig.json:

Terminal window
FORGE_LOG=debug forge index . 2>&1 | grep "tsconfig"

If Forge found and read your tsconfig.json, aliases defined in compilerOptions.paths are resolved automatically.

If aliases still don’t resolve after indexing, add them explicitly to .forge/config.toml:

[resolve]
aliases = [
{ alias = "@app", target = "src" },
{ alias = "@shared", target = "packages/shared/src" },
{ alias = "~", target = "src" },
]

Re-run forge index . after adding aliases. Then re-run forge_trace_imports to verify the imports resolve.

forge_check_wiring tells you whether a module is reachable from any entry point:

Via MCP:

Call forge_check_wiring on src/lib/payments.ts

Expected output when reachable:

forge_check_wiring: src/lib/payments.ts
Reachable: YES
Entry point: src/index.ts
Path: src/index.ts → src/api/orders.ts → src/lib/payments.ts (3 hops)

Expected output when unreachable:

forge_check_wiring: src/lib/old-payments.ts
Reachable: NO
No path from any entry point to this file.
Imported by: 0 files
Note: this file may be dead code or a new module not yet wired in.

Unreachable modules aren’t necessarily broken — they might be utilities called at runtime via dynamic import, new modules not yet connected, or intentionally standalone scripts. Use context to determine if “unreachable” is a real problem.

If you know a symbol exists but can’t find it in Forge’s results:

Terminal window
forge search --symbols "createPayment"

Or via MCP:

Call forge_search_symbols with query="createPayment"

If the symbol doesn’t appear, it wasn’t extracted. Go back to Step 1 and check forge_parse_file for the file you expect it to be in.

Terminal window
forge health

Look for:

  • broken_import — an import that doesn’t resolve to any file
  • unresolved_module — a module-level import that Forge couldn’t find
  • missing_export — a symbol is imported somewhere but not exported from the source

These findings point directly to resolution failures.

TypeScript barrel files (index.ts re-exports)

If a file re-exports symbols from other modules with export * from './payments', Forge tracks these re-exports. But if the barrel file itself is in ignored_paths or has a parse error, downstream imports that go through it appear broken.

Check the barrel file:

Call forge_parse_file on src/lib/index.ts

If it shows no exports, the barrel file isn’t parsing correctly. Check for syntax errors.

Dynamic imports

import(...) is a dynamic import and Forge tracks it separately from static imports. forge_trace_imports includes dynamic imports in its output, but they’re marked as DYNAMIC:

import('../plugins/' + pluginName) → DYNAMIC (unresolvable at index time)

Dynamic imports with variable paths can’t be resolved statically — this is expected, not a bug.

Non-standard import syntax

Some tools and frameworks use non-standard import syntax (Webpack magic comments, Vite’s import.meta.glob, etc.). Forge may not recognize these as imports. If a widely-used file shows 0 imports in forge_parse_file, it likely uses custom syntax.

Workaround: add the file to ignored_paths if it’s causing false positive health findings, or use forge_search to find references manually.

forge_trace_dependents returns fewer results than expected

forge_trace_dependents returns only files that statically import the target. Files that reference it via a string path (e.g., require('./payments') in a config file, or a dynamic import(path)) don’t appear. This is a limitation of static analysis, not a bug.