{"record":{"id":"182ff713d7ec8b08","repo":"windmill-labs/windmill","slug":"multiple-repositories-found-repopaths-join","errorCode":null,"errorMessage":"Multiple repositories found: ${repoPaths.join(\", \")}. Use --repository to specify which one to ${operation || \"use\"}.","messagePattern":"Multiple repositories found: (.+?)\\. Use --repository to specify which one to (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/utils/utils.ts","lineNumber":266,"sourceCode":"  }\n\n  if (repositories.length === 1) {\n    const repoPath = repositories[0].git_repo_resource_path.replace(\n      /^\\$res:/,\n      \"\"\n    );\n    log.info(colors.cyan(`Auto-selected repository: ${colors.bold(repoPath)}`));\n    return repositories[0];\n  }\n\n  // Check if we're in a non-interactive environment\n  const isInteractive = !!process.stdin.isTTY && !!process.stdout.isTTY;\n\n  if (!isInteractive) {\n    const repoPaths = repositories.map((r) =>\n      r.git_repo_resource_path.replace(/^\\$res:/, \"\")\n    );\n    throw new Error(\n      `Multiple repositories found: ${repoPaths.join(\n        \", \"\n      )}. Use --repository to specify which one to ${operation || \"use\"}.`\n    );\n  }\n\n  // Import Select dynamically to avoid dependency issues\n  const { Select } = await import(\"@cliffy/prompt/select\");\n\n  console.log(\n    `\\nMultiple repositories found. Please select which repository to ${\n      operation || \"use\"\n    }:\\n`\n  );\n\n  const selectedRepo = await Select.prompt({\n    message: `Select repository for ${operation || \"operation\"}:`,\n    options: repositories.map((repo, index) => {","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/utils/utils.ts#L248-L284","documentation":"When a workspace has multiple git-sync repositories and the CLI session is non-interactive (no TTY), `selectRepository` cannot prompt for a choice, so it throws listing all repository paths and tells the caller to pass `--repository`.","triggerScenarios":"Running any repository-scoped CLI command with 2+ repositories configured while stdin/stdout are not TTYs (CI pipelines, scripts, piped output), without the `--repository` flag.","commonSituations":"CI/CD jobs (GitHub Actions, GitLab CI) after a second repo was added to the workspace; running the CLI under a wrapper that hides the TTY.","solutions":["Pass the repository explicitly: add `--repository <repo-path>` to the command","Run in an interactive terminal to get the selection prompt","Remove or consolidate unused repositories so only one remains (then selection is automatic)"],"exampleFix":"// before (CI, non-interactive)\nwmill git-sync pull\n// Multiple repositories found: repo_a, repo_b ...\n// after\nwmill git-sync pull --repository repo_a","handlingStrategy":"validation","validationCode":"const repos = await client.listGitSyncRepositories();\nif (repos.length > 1 && !process.stdout.isTTY && !process.env.CI_REPO_FLAG_SET) {\n  throw new Error('Non-interactive session with multiple repos: pass --repository <path>');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runGitSyncCommand();\n} catch (e) {\n  if (e.message.startsWith('Multiple repositories found:')) {\n    const first = e.message.match(/found: ([^.]*)/)?.[1].split(', ')[0];\n    console.error(`Re-run with --repository ${first} (or your choice).`);\n  } else throw e;\n}","preventionTips":["Always pass --repository explicitly in CI/scripts; don't rely on interactive prompts","Keep one default repository per workspace when automation is involved","If shells hide TTY status (piped output), force explicit flags"],"tags":["cli","git-sync","non-interactive","ci","ambiguous-argument"],"backgroundTag":"ambiguous-target-non-interactive","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}