abhigyanpatwari/GitNexus · warning

[python-workspace-extractor] duplicate package "${manifest.n

Error message

[python-workspace-extractor] duplicate package "${manifest.name}" in "${groupPath}" and "${existing.groupPath}" — skipping "${groupPath}"

What it means

Emitted by the group Python workspace extractor. Two scanned directories produced manifests whose import name (importName) is identical; packages are keyed by importName in a packagesByImportName map, so the later registration (groupPath) is skipped and its workspace dependency links are never built. Cross-repo resolution for the skipped package degrades after this warning.

Source

Thrown at gitnexus/src/core/group/extractors/python-workspace-extractor.ts:214

  const packagesByGroupPath = new Map<string, PythonPackageMeta>();

  for (const [groupPath] of Object.entries(repos)) {
    const repoPath = repoPaths.get(groupPath);
    if (!repoPath) continue;

    const manifest = await parsePythonManifest(repoPath);
    if (!manifest) continue;

    const meta: PythonPackageMeta = {
      name: manifest.name,
      importName: manifest.importName,
      groupPath,
      repoPath,
      workspaceDeps: manifest.deps,
    };
    const existing = packagesByImportName.get(manifest.importName);
    if (existing) {
      logger.warn(
        `[python-workspace-extractor] duplicate package "${manifest.name}" in "${groupPath}" and "${existing.groupPath}" — skipping "${groupPath}"`,
      );
      continue;
    }
    packagesByImportName.set(manifest.importName, meta);
    packagesByGroupPath.set(groupPath, meta);
  }

  const links: GroupManifestLink[] = [];
  const seen = new Set<string>();

  for (const [, pkg] of packagesByGroupPath) {
    const normalizedDeps = pkg.workspaceDeps.map((d) => d.replace(/-/g, '_'));
    const groupPkgDeps = normalizedDeps.filter((d) => packagesByImportName.has(d));
    if (groupPkgDeps.length === 0) continue;

    const knownPackages = new Map<string, string>();
    for (const dep of groupPkgDeps) {

View on GitHub (pinned to 52924ef12c)

Solutions

  1. Rename the duplicate package's project name and top-level import package so importName is unique
  2. Ignore or remove the vendored duplicate so the extractor does not scan it
  3. Re-run group analyze and verify the warning disappears and workspace links resolve

Example fix

# before — repo-b/pyproject.toml
[project]
name = "payments-lib"

# after
[project]
name = "payments-lib-v2"  # rename the import package dir to match
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'node:fs';
import { join } from 'node:path';

function assertUniquePythonImports(repoDirs: string[]): void {
  const seen = new Map<string, string>();
  for (const dir of repoDirs) {
    let name: string | undefined;
    try {
      const raw = JSON.parse(readFileSync(join(dir, 'pyproject.json-dump'), 'utf8')); // or parse TOML
      name = raw?.project?.name ?? raw?.tool?.poetry?.name;
    } catch {
      continue;
    }
    if (!name) continue;
    const importName = name.replaceAll('-', '_').replaceAll('.', '_');
    if (seen.has(importName)) {
      throw new Error(`duplicate import "${importName}" in ${seen.get(importName)} and ${dir}`);
    }
    seen.set(importName, dir);
  }
}

Type guard

function hasUniqueImports<T extends { importName: string }>(items: readonly T[]): boolean {
  return new Set(items.map((i) => i.importName)).size === items.length;
}

Prevention

When it happens

Trigger: A group contains two pyproject.toml/setup.py declaring the same project or import name — a library vendored into a second repo, or two packages whose top-level module directory resolves to the same import name.

Common situations: Forked Python packages kept in one group; duplicated internal utility libraries; src-layout packages that both expose the same top-level module name.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@52924ef12c (2026-08-20). Data as JSON: /api/errors/6a6bcb0a11463052. Report an issue: GitHub.