abhigyanpatwari/GitNexus · warning

interface-dispatch: members over the fan-out cap dropped imp

Error message

interface-dispatch: members over the fan-out cap dropped implementors (their CALLS edges were not emitted)

What it means

During scope-resolution emit, the interface-dispatch pass fans a call through an interface member out to CALLS edges for each of its implementors. When a member has more implementors than MAX_INTERFACE_DISPATCH_FANOUT (default 32, overridable via GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT), the overflow implementors get no CALLS edges at all. The pipeline warns (#2829 contract) so the coverage loss is visible, because impact() on those dropped implementations would otherwise silently under-report.

Source

Thrown at gitnexus/src/core/ingestion/scope-resolution/pipeline/run.ts:1054

          recordResolutionOutcome,
          calleeIdSink: calleeIdAccumulator,
          // The pass's only source of positive EXTERNAL evidence for a dropped
          // receiver (`console.log`, `fetch(...)`). Same hook, same spelling as
          // the `emitFreeCallFallback` wiring below.
          isBuiltInName: provider.languageProvider.isBuiltInName,
          // What each heritage clause instantiated its base with, so the
          // interface-dispatch fan-out can refuse an incompatible instantiation
          // (#2912). Empty under `callableFlowOnly`, which emits no dispatch.
          heritageTypeArguments,
        },
      );
  const receiverExtras = receiverBound.emitted;
  if (receiverBound.dispatchFanoutSkipped > 0) {
    // Never drop dispatch coverage silently (#2829) — same contract as the
    // property-dispatch cap below. An interface member over the cap loses real
    // implementors, so `impact()` on those implementations under-reports; an
    // operator has to be able to see WHICH member lost them.
    logger.warn(
      {
        lang: provider.language,
        dispatchFanoutSkipped: receiverBound.dispatchFanoutSkipped,
        dispatchFanoutSkippedNames: receiverBound.dispatchFanoutSkippedNames,
        fanoutCap: MAX_INTERFACE_DISPATCH_FANOUT,
      },
      'interface-dispatch: members over the fan-out cap dropped implementors (their CALLS edges were not emitted)',
    );
  }
  const unresolvedReceiverExtras =
    !callableFlowOnly && provider.emitUnresolvedReceiverEdges !== undefined
      ? provider.emitUnresolvedReceiverEdges(
          graph,
          indexes,
          emitParsedFiles,
          postHeritageNodeLookup,
          handledSites,
          readonlyModel,

View on GitHub (pinned to 0d1aed942f)

Solutions

  1. Set GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT to a value above your widest interface (e.g. 128) and re-run analyze
  2. Read dispatchFanoutSkippedNames in the warn to find the exact member(s), then verify with impact() on the implementors after re-indexing
  3. If the wide interface is test-mock noise, exclude generated/mock paths from indexing so the cap is not consumed by uninformative targets
  4. Keep the override bounded — the fan-out is a per-call-site product, so huge caps multiply graph size without adding actionable information

Example fix

# before
export GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT=   # unset → default 32, warn fires
npx gitnexus analyze
# after
export GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT=128
npx gitnexus analyze   # warn disappears; CALLS to implementors emitted
Defensive patterns

Strategy: validation

Validate before calling

// Before trusting impact() results, assert the emit logs are cap-clean:
import { execSync } from 'node:child_process';
const out = execSync('npx gitnexus analyze 2>&1', { encoding: 'utf8' });
if (out.includes('interface-dispatch: members over the fan-out cap')) {
  throw new Error('impact() would under-report: raise GITNEXUS_MAX_INTERFACE_DISPATCH_FANOUT');
}

Prevention

When it happens

Trigger: Running analyze (emit phase, not callableFlowOnly) on a repo where one interface member is implemented by more than 32 types (mock proliferation is the usual cause); the receiverBound result reports dispatchFanoutSkipped > 0 and the orchestrator logs the warn with language, skipped count, skipped member names (bounded to 20 samples), and the cap.

Common situations: Large TypeScript/Java codebases with heavy interface mocking in tests, DI containers registering many implementors, generated code merging dozens of classes under one interface, or someone lowering the fan-out cap env below the repo's real implementor count.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@0d1aed942f (2026-08-20). Data as JSON: /api/errors/74057e2dffc7f5f0. Report an issue: GitHub.