paperclipai/paperclip · error · Error

Failed to reset local git index to HEAD after workspace rest

Error message

Failed to reset local git index to HEAD after workspace restore: ${detail}

What it means

Thrown by resetLocalGitIndexToHead when `git reset --quiet HEAD -- .` fails. This runs after a workspace restore to ensure the git index matches HEAD. The error detail includes the git error message, stderr, and stdout concatenated so the developer can see the underlying git failure.

Source

Thrown at packages/adapter-utils/src/git-workspace-sync.ts:484

export async function resetLocalGitIndexToHead(input: {
  localDir: string;
  checkWorkingTreeClean?: boolean;
}): Promise<void> {
  try {
    await runLocalGit(input.localDir, ["reset", "--quiet", "HEAD", "--", "."], {
      timeout: 60_000,
      maxBuffer: 1024 * 1024,
    });
  } catch (error) {
    const detail = error && typeof error === "object"
      ? [
        (error as { message?: unknown }).message,
        (error as { stderr?: unknown }).stderr,
        (error as { stdout?: unknown }).stdout,
      ].filter((value): value is string => typeof value === "string" && value.trim().length > 0).join("\n")
      : String(error);
    throw new Error(`Failed to reset local git index to HEAD after workspace restore: ${detail}`);
  }

  const stagedDiff = await runLocalGit(input.localDir, ["diff", "--cached", "--name-status", "HEAD", "--"], {
    timeout: 10_000,
    maxBuffer: 1024 * 1024,
  });
  if (stagedDiff.stdout.trim().length > 0) {
    throw new Error(
      `Workspace restore left staged git index changes after reset:\n${stagedDiff.stdout.trim()}`,
    );
  }

  if (!input.checkWorkingTreeClean) return;

  const workingTreeDiff = await runLocalGit(input.localDir, ["diff", "--name-status", "HEAD", "--"], {
    timeout: 10_000,
    maxBuffer: 1024 * 1024,
  });

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Check the detail string for the specific git error (e.g. 'fatal: not a git repository', 'failed to read index').
  2. Run `git fsck --full` in the localDir to check for repo corruption.
  3. If the repo is empty (no HEAD), ensure the workspace clone completed before calling resetLocalGitIndexToHead.
  4. Re-clone or re-restore the workspace if the git repo is corrupt beyond repair.
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the git repo is healthy before resetting
async function isGitRepoHealthy(localDir: string): Promise<boolean> {
  try {
    const result = await runLocalGit(localDir, ["rev-parse", "--verify", "HEAD"], { timeout: 5_000, maxBuffer: 1024 });
    return (result.exitCode ?? 1) === 0;
  } catch {
    return false;
  }
}

Try / catch

try {
  await resetLocalGitIndexToHead({ localDir, checkWorkingTreeClean: true });
} catch (err) {
  if (err instanceof Error && err.message.includes("Failed to reset local git index to HEAD")) {
    // The detail string reveals the git-level failure
    logger.error(`Git index reset failed: ${err.message}`);
    // Consider re-cloning the workspace if the repo is corrupt
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling resetLocalGitIndexToHead({ localDir, checkWorkingTreeClean }) where runLocalGit for `git reset --quiet HEAD -- .` throws. The catch block assembles a detail string from error.message, error.stderr, and error.stdout.

Common situations: The local git repo has no HEAD (empty repo with no commits); the index is corrupt (git reset cannot read it); a file in the working tree has a name that git cannot handle; disk I/O errors on the local filesystem; the repo was partially restored and is in an inconsistent state.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/d1f925ae667c2716. Report an issue: GitHub.