yamadashy/repomix · error · RepomixError

Refusing to trust ${configName}: the remote repository's con

Error message

Refusing to trust ${configName}: the remote repository's config must be a regular file, not a symlink.

What it means

Repomix refuses to trust a config file from a cloned remote repository when the resolved config path is a symlink or not a regular file. Git preserves symlinks, so a remote repo can ship e.g. repomix.config.json as a symlink pointing outside the owner-only temp clone dir; the reviewed bytes could come from an unrelated local file and the target could be swapped between review and load. assertConfigIsContained lstat()s the path and throws this RepomixError before any trust decision, and this check runs even under --force and in non-interactive (CI) runs.

Source

Thrown at src/cli/prompts/remoteConfigTrustPrompt.ts:112

};

/**
 * Reject a config that is not a regular file inside the cloned repo. A repository
 * can ship `repomix.config.js` as a symlink (git preserves symlinks on POSIX), and
 * config resolution follows it. That would let the reviewed bytes come from outside
 * the owner-only temp dir: the content shown could be an unrelated local file, and
 * the target could be swapped between this read and the later load. Everything we
 * show the user must live in the tree we just cloned.
 */
const assertConfigIsContained = async (
  configPath: string,
  repoDir: string,
  deps: Pick<ConfirmRemoteConfigTrustDeps, 'lstat' | 'realpath'>,
): Promise<void> => {
  const configName = path.basename(configPath);
  const stats = await deps.lstat(configPath);
  if (stats.isSymbolicLink() || !stats.isFile()) {
    throw new RepomixError(
      `Refusing to trust ${configName}: the remote repository's config must be a regular file, not a symlink.`,
    );
  }

  const [realConfigPath, realRepoDir] = await Promise.all([deps.realpath(configPath), deps.realpath(repoDir)]);
  const relative = path.relative(realRepoDir, realConfigPath);
  if (relative.startsWith('..') || path.isAbsolute(relative)) {
    throw new RepomixError(`Refusing to trust ${configName}: it resolves outside the cloned repository.`);
  }
};

/**
 * Interactively confirm before a cloned remote repository's config is trusted
 * (via `--remote-trust-config` / `REPOMIX_REMOTE_TRUST_CONFIG`). Shows the config
 * that is about to run, then asks the user. Throws `OperationCancelledError` when
 * the user declines.
 *
 * Proceeds without prompting when: `--force` is passed, the shell is

View on GitHub (pinned to f465ad9093)

Solutions

  1. Replace the symlink with a regular file in the remote repo (git rm the link, copy the real file in, commit).
  2. Verify what the path points at: `git ls-files -s` in the repo shows mode 120000 for symlinks; use `file repomix.config.*` locally after cloning.
  3. If you own the repo, check your build/tooling for steps that create symlinks named repomix.config.* before publishing.
  4. If you cannot change the repo, pass an explicit regular-file config with `--config /path/to/local.config.json` (explicit --config skips the remote config entirely).

Example fix

# before (in the remote repo)
repomix.config.json -> /shared/configs/repomix.json  (symlink, mode 120000)

# after
git rm repomix.config.json
cp /shared/configs/repomix.json repomix.config.json
git add repomix.config.json && git commit -m "replace config symlink with regular file"
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs/promises';
const stats = await fs.lstat(configPath);
if (stats.isSymbolicLink() || !stats.isFile()) {
  throw new Error(`Refusing to use ${configPath}: must be a regular file, not a symlink`);
}

Type guard

const isRegularFile = (stats: fs.Stats): boolean => stats.isFile() && !stats.isSymbolicLink();

Try / catch

try {
  await runRemotePack();
} catch (e) {
  if (e instanceof RepomixError && e.message.includes('must be a regular file, not a symlink')) {
    console.error('Remote repo ships a symlinked config; replace it with a real file or use --config.');
  } else throw e;
}

Prevention

When it happens

Trigger: Running `repomix --remote <url>` (with --remote-trust-config or REPOMIX_REMOTE_TRUST_CONFIG, or interactively) where the cloned repo contains a config file (repomix.config.ts/js/json5/etc.) that is a symbolic link, or a special file (FIFO, device, directory) rather than a regular file. Thrown by assertConfigIsContained via confirmRemoteConfigTrust before readFile/prompt.

Common situations: A malicious or misconfigured repo symlinks its config to /etc/passwd or a file outside the temp clone; a developer generates configs as symlinks to shared templates; a dotfile manager (e.g. GNU Stow, chezmoi) replaced the config with a symlink in the shipped repo.

Related errors


AI-assisted analysis of yamadashy/repomix@f465ad9093 (2026-08-29). Data as JSON: /api/errors/d6e4a6fe572148e6. Report an issue: GitHub.