{"record":{"id":"72a70a50a2e1f4bd","repo":"abhigyanpatwari/GitNexus","slug":"rust-workspace-extractor-duplicate-crate-name","errorCode":null,"errorMessage":"[rust-workspace-extractor] duplicate crate name \"${manifest.name}\" in \"${groupPath}\" and \"${existing.groupPath}\" — skipping \"${groupPath}\"","messagePattern":"\\[rust-workspace-extractor\\] duplicate crate name \"(.+?)\" in \"(.+?)\" and \"(.+?)\" — skipping \"(.+?)\"","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gitnexus/src/core/group/extractors/rust-workspace-extractor.ts","lineNumber":251,"sourceCode":"  const cratesByName = new Map<string, CrateMeta>();\n  const cratesByGroupPath = new Map<string, CrateMeta>();\n\n  for (const [groupPath] of Object.entries(repos)) {\n    const repoPath = repoPaths.get(groupPath);\n    if (!repoPath) continue;\n\n    const manifest = await parseCrateManifest(repoPath);\n    if (!manifest) continue;\n\n    const meta: CrateMeta = {\n      name: manifest.name,\n      groupPath,\n      repoPath,\n      workspaceDeps: manifest.workspaceDeps,\n    };\n    const existing = cratesByName.get(manifest.name);\n    if (existing) {\n      logger.warn(\n        `[rust-workspace-extractor] duplicate crate name \"${manifest.name}\" in \"${groupPath}\" and \"${existing.groupPath}\" — skipping \"${groupPath}\"`,\n      );\n      continue;\n    }\n    cratesByName.set(manifest.name, meta);\n    cratesByGroupPath.set(groupPath, meta);\n  }\n\n  // Phase 2: For each crate, identify which of its workspace deps are\n  // also in this group (i.e., repos we can link to)\n  const links: GroupManifestLink[] = [];\n  const seen = new Set<string>();\n\n  for (const [, crate] of cratesByGroupPath) {\n    const groupCrateDeps = crate.workspaceDeps.filter((d) => cratesByName.has(d));\n    if (groupCrateDeps.length === 0) continue;\n\n    // Phase 3: Scan source files for imports from workspace deps","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/core/group/extractors/rust-workspace-extractor.ts#L233-L269","documentation":"Emitted by the group Rust workspace extractor. Two scanned directories produced Cargo.toml manifests with the same crate \"name\"; crates are keyed by name in a cratesByName map, so the later registration (groupPath) is skipped and Phase 2 linking never runs for it. Workspace dependency links for the skipped crate are silently absent after this warning.","triggerScenarios":"A group contains two workspace members (or two group repos) whose Cargo.toml both declare e.g. name = \"common-utils\": a vendored crate copy, a fork that kept the original crate name, or a template member instantiated twice.","commonSituations":"Vendored crates duplicated inside a group repo; forked crates that kept the upstream name; example workspace members copying a real crate's name.","solutions":["Rename the duplicate crate's name in Cargo.toml (and any path dependencies referencing it)","If one copy is vendored or generated, add it to ignore rules so the extractor skips it","Remove or merge the stale duplicate","Re-run group analyze and confirm the warning is gone and crate links resolve"],"exampleFix":"# before — crates/b/Cargo.toml\n[package]\nname = \"common-utils\"\nversion = \"0.2.0\"\n\n# after\n[package]\nname = \"common-utils-v2\"\nversion = \"0.2.0\"","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nfunction assertUniqueCrateNames(repoDirs: string[]): void {\n  const seen = new Map<string, string>();\n  for (const dir of repoDirs) {\n    let name: string | undefined;\n    try {\n      const toml = readFileSync(join(dir, 'Cargo.toml'), 'utf8');\n      name = /^name\\s*=\\s*\"([^\"]+)\"/m.exec(toml)?.[1];\n    } catch {\n      continue;\n    }\n    if (!name) continue;\n    if (seen.has(name)) {\n      throw new Error(`duplicate crate name \"${name}\" in ${seen.get(name)} and ${dir}`);\n    }\n    seen.set(name, dir);\n  }\n}","typeGuard":"function hasUniqueCrateNames<T extends { name: string }>(items: readonly T[]): boolean {\n  return new Set(items.map((i) => i.name)).size === items.length;\n}","tryCatchPattern":null,"preventionTips":["Keep Cargo.toml package names unique across every repo in the group","Update path/workspace dependencies when renaming a crate so old names do not linger","Add a CI lint that rejects duplicate crate names before group analysis runs"],"tags":["rust","workspace","cargo","monorepo","duplicate-name"],"backgroundTag":"duplicate-package-name","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}