gastownhall/beads · error

failed to untrack last-touched file: %w

Error message

failed to untrack last-touched file: %w

What it means

FixLastTouchedTracking untracks the machine-local .beads/last-touched file with `git rm --cached <lastTouchedPath>` so it is no longer committed while keeping the local copy. This error wraps a non-zero exit of that git command. Like the redirect fix, the root cause lies in git's index/repository state.

Source

Thrown at cmd/bd/doctor/gitignore.go:707

func FixLastTouchedTracking(repoPath string) error {
	lastTouchedPath := filepath.Join(repoPath, ".beads", "last-touched")

	// Check if file is actually tracked first
	cmd := exec.Command("git", "ls-files", lastTouchedPath) // #nosec G204 - args are hardcoded paths
	output, err := cmd.Output()
	if err != nil {
		return nil // Not a git repo, nothing to do
	}

	trackedPath := strings.TrimSpace(string(output))
	if trackedPath == "" {
		return nil // Not tracked, nothing to do
	}

	// Untrack the file (keeps the local copy)
	cmd = exec.Command("git", "rm", "--cached", lastTouchedPath) // #nosec G204 - args are hardcoded paths
	if err := cmd.Run(); err != nil {
		return fmt.Errorf("failed to untrack last-touched file: %w", err)
	}

	return nil
}

// CheckProjectGitignore checks if the project-root .gitignore contains patterns
// to prevent accidentally committing Dolt database files and credential keys.
// repoPath is the project root directory.
func CheckProjectGitignore(repoPath string) DoctorCheck {
	gitignorePath := filepath.Join(repoPath, ".gitignore")

	content, err := os.ReadFile(gitignorePath) // #nosec G304 -- path is hardcoded
	if err != nil {
		if os.IsNotExist(err) {
			return DoctorCheck{
				Name:    "Project Gitignore",
				Status:  StatusWarning,
				Message: "No project .gitignore found — Dolt/credential files may be committed accidentally",

View on GitHub (pinned to 71377f2769)

Solutions

  1. Run `git rm --cached .beads/last-touched` manually to see git's real error
  2. Finish or abort any in-progress merge/rebase (`git status`) and retry
  3. Verify tracking state: `git ls-files .beads/last-touched`; if empty, the file is already untracked and no fix is needed
  4. Run bd from within the repository containing .beads/ so git resolves the correct index

Example fix

// before: file tracked, untrack fails during rebase
$ bd doctor --fix
failed to untrack last-touched file: exit status 1
// after
$ git rebase --abort
$ bd doctor --fix  # untracks .beads/last-touched, keeps local copy
Defensive patterns

Strategy: validation

Validate before calling

const tracked = execSync('git ls-files -- .beads/last-touched', { encoding: 'utf8' }).trim();
const midOp = execSync('git status --porcelain', { encoding: 'utf8' }).split('\n').some(l => /^(UU|AA|DD|REBASE|MERGE)/.test(l));
if (midOp) throw new Error('finish or abort merge/rebase before bd doctor --fix');
if (!tracked) console.log('.beads/last-touched already untracked');

Try / catch

try {
  execSync('bd doctor --fix', { stdio: 'inherit' });
} catch (err) {
  if (String(err.stderr).includes('failed to untrack last-touched file')) {
    console.error('git state:', execSync('git status --short', { encoding: 'utf8' }));
  }
  throw err;
}

Prevention

When it happens

Trigger: FixLastTouchedTracking detects last-touched is tracked and runs `git rm --cached lastTouchedPath`; git exits non-zero because the file is not in the index, a merge/rebase is in progress, the path differs from the index entry, or the directory is not a git repository.

Common situations: last-touched was committed before the ignore rule existed; stale index entries after moving .beads/; running bd outside the repo; CI environments with detached/incomplete checkouts; git hooks failing on index operations.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/d7c66f5047342669. Report an issue: GitHub.