abhigyanpatwari/GitNexus · error

Duplicate auto-sync targetDir ${targetDir} for ${previous} a

Error message

Duplicate auto-sync targetDir ${targetDir} for ${previous} and ${remoteUrl}

What it means

buildWorkItems derives a targetDir for each remote URL of a project and enforces that each target directory is owned by exactly one remote URL. If two remote URLs resolve to the same local clone path, the run would race or clobber files, so it throws instead of proceeding.

Source

Thrown at gitnexus/src/core/auto-sync/runner.ts:461

  const items: AutoSyncWorkItem[] = [];
  const targetOwners = new Map<string, string>();
  for (const project of config.projects) {
    let cloneRoot: AutoSyncWorkItem['cloneRoot'];
    try {
      cloneRoot = await deps.resolveCloneRoot(project.localPath);
    } catch (err: unknown) {
      for (const remoteUrl of project.remoteUrls) {
        items.push({ project, remoteUrl, error: shortErrorMessage(err) });
      }
      continue;
    }
    for (const remoteUrl of project.remoteUrls) {
      try {
        const repoName = extractRepoNameFromRemoteUrl(remoteUrl);
        const targetDir = getConfiguredRepoPath({ localPath: cloneRoot.root }, repoName, remoteUrl);
        const previous = targetOwners.get(targetDir);
        if (previous !== undefined) {
          throw new Error(
            `Duplicate auto-sync targetDir ${targetDir} for ${previous} and ${remoteUrl}`,
          );
        }
        targetOwners.set(targetDir, remoteUrl);
        items.push({ project, remoteUrl, cloneRoot, repoName, targetDir });
      } catch (err: unknown) {
        items.push({ project, remoteUrl, error: shortErrorMessage(err) });
      }
    }
  }
  return items;
}

async function mapWithConcurrency<T, R>(
  items: T[],
  concurrency: number,
  signal: AbortSignal | undefined,
  worker: (item: T) => Promise<R>,

View on GitHub (pinned to 0d1aed942f)

Solutions

  1. Remove the duplicate remote URL from the project's remoteUrls config so each URL maps to a unique targetDir.
  2. Configure a distinct clone root or repo path override (getConfiguredRepoPath) so colliding repos get separate directories.
  3. Normalize your remote URLs to one scheme (all https or all ssh) to avoid scheme-based name collisions.
  4. Rename one of the repos if two repo names resolve to the same directory name.

Example fix

// before (project config)
"remoteUrls": ["https://github.com/acme/api.git", "git@github.com:acme/api.git"]
// after
"remoteUrls": ["https://github.com/acme/api.git"]
Defensive patterns

Strategy: validation

Validate before calling

const dirs = project.remoteUrls.map((u) =>
  getConfiguredRepoPath({ localPath: cloneRoot.root }, extractRepoNameFromRemoteUrl(u), u),
);
if (new Set(dirs).size !== dirs.length) {
  throw new Error('remoteUrls resolve to duplicate target directories');
}

Try / catch

try {
  items = await workItems();
} catch (err) {
  if (String(err.message).startsWith('Duplicate auto-sync targetDir')) {
    logger.error('fix project remoteUrls:', err.message);
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling buildWorkItems (via workItems) for a project whose remoteUrls list contains two URLs (e.g. https and ssh forms, or duplicates) that extractRepoNameFromRemoteUrl + getConfiguredRepoPath collapse into the same targetDir.

Common situations: A project configured with both an HTTPS and an SSH remote for the same repo; a copy-pasted duplicate remote URL; two distinct repos whose names normalize to the same directory in the clone root.

Related errors


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