prisma/prisma · error · ShellConfigError

${shellName} re-exports ${mapping.package}, which has no pub

Error message

${shellName} re-exports ${mapping.package}, which has no public shell mapping

What it means

For each entry in shell.reexports, shell-build looks up mapping.package in the internal-package table built from all shells. If no shell publishes that package, the reexport target does not exist as a single-instance module and the build throws. The rewrite plugin that turns '@internal/...' imports into published specifiers would have nothing to rewrite to.

Source

Thrown at packages/0-config/tsdown/shell-build.ts:140

        }
      }
      aggregates.set(pkg.entry, expected);
      const entryFile = addEntry(pkg.entry, `${pkg.entry}.ts`);
      writeFileSync(
        entryFile,
        `${aggregated.map(({ specifier }) => `export * from '${specifier}';`).join('\n')}\n`,
      );
    }
  }

  // Forwarded surfaces: the generated modules import the sibling package by
  // its internal name, which the rewrite plugin turns into that sibling's
  // published entrypoint and marks external. Nothing is copied, so the
  // forwarded modules stay single-instance across the whole install.
  for (const mapping of shell.reexports ?? []) {
    const source = lookup.get(mapping.package);
    if (source === undefined) {
      throw new ShellConfigError(
        `${shellName} re-exports ${mapping.package}, which has no public shell mapping`,
      );
    }
    if (source.shell === shellName) {
      throw new ShellConfigError(
        `${shellName} re-exports ${mapping.package}, which it already publishes directly`,
      );
    }
    const hasSourceRootExport = Object.hasOwn(source.exports, '.');
    if (mapping.root !== false && mapping.subpaths === undefined && !hasSourceRootExport) {
      // No root export upstream: forward the sibling shell's synthesized
      // package-level aggregate, which carries no default export.
      const entryFile = addEntry(mapping.entry, `${mapping.entry}.ts`);
      writeFileSync(entryFile, `export * from '${mapping.package}';\n`);
    }
    const forwarded = mapping.subpaths;
    if (forwarded !== undefined) {
      const available = new Set(

View on GitHub (pinned to a20d61fb6f)

Solutions

  1. Map the package into a shell first (add it to that shell's packages array in @internal/publish-surface/shells), then reference it from reexports.
  2. If the reexport is stale (the package no longer exists), delete the mapping entry.
  3. Confirm mapping.package matches the exact published name of the source package.

Example fix

// before — reexports references an unmapped package
reexports: [{ package: '@internal/missing', entry: 'missing' }]
// Error: @prisma/orm-framework re-exports @internal/missing, which has no public shell mapping

// after — add @internal/missing to some shell's packages[], or drop the reexport
reexports: [{ package: '@internal/real', entry: 'real' }]
Defensive patterns

Strategy: validation

Validate before calling

function assertReexportMapped(
  packageName: string,
  lookup: Map<string, InternalPackage>,
): void {
  if (!lookup.has(packageName)) {
    throw new Error(
      `${packageName} has no public shell mapping; add it to some shell's packages[] first`,
    );
  }
}

Type guard

function isMappedPackage(name: string, lookup: Map<string, unknown>): boolean {
  return lookup.has(name);
}

Prevention

When it happens

Trigger: A reexport mapping references a package name that is not listed in any shell's packages array in @internal/publish-surface/shells; the package was renamed; the mapping was copy-pasted from another shell.

Common situations: Adding a reexport before adding the source package to its shell; removing a package from publicShells but leaving a dangling reexport; typo in the mapping.package value.

Related errors


AI-assisted analysis of prisma/prisma@a20d61fb6f (2026-08-11). Data as JSON: /api/errors/edc746f203050404. Report an issue: GitHub.