gastownhall/beads · error

checking sidecar %s: %w

Error message

checking sidecar %s: %w

What it means

This wraps an os.Stat failure on the retire op's source sidecar during retirement. pathExists distinguishes only 'exists' vs os.ErrNotExist; any other stat error (permission, I/O) surfaces here. The retire step aborts mid-apply, so earlier operations may already have been applied.

Source

Thrown at cmd/bd/migrate_hooks_apply.go:385

		if err != nil {
			return fmt.Errorf("comparing sidecars %s and %s: %w", op.SourcePath, op.DestinationPath, err)
		}
		if !equal {
			return fmt.Errorf(
				"artifact collision for %s: %s already exists with different content",
				op.SourcePath,
				op.DestinationPath,
			)
		}
	}

	return nil
}

func retireHookSidecar(op hookMigrationRetireOp) (string, error) {
	sourceExists, err := pathExists(op.SourcePath)
	if err != nil {
		return "", fmt.Errorf("checking sidecar %s: %w", op.SourcePath, err)
	}
	if !sourceExists {
		return "", nil
	}

	destinationExists, err := pathExists(op.DestinationPath)
	if err != nil {
		return "", fmt.Errorf("checking sidecar destination %s: %w", op.DestinationPath, err)
	}

	if destinationExists {
		equal, err := filesEqual(op.SourcePath, op.DestinationPath)
		if err != nil {
			return "", fmt.Errorf("comparing sidecar %s to %s: %w", op.SourcePath, op.DestinationPath, err)
		}
		if !equal {
			return "", fmt.Errorf("artifact collision for %s: %s already exists with different content", op.SourcePath, op.DestinationPath)
		}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped error and stat the source path manually to identify the failing component.
  2. Restore access to the source directory (chown/chmod or remount).
  3. Re-run the migration once access is restored — already-completed retire ops are idempotent (missing sources are skipped).

Example fix

// before
$ ls -ld /path/to/source-dir
perms: root-only
// after
$ sudo chmod a+rx /path/to/source-dir
$ bd migrate
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(filepath.Dir(op.SourcePath)); err != nil {
	return fmt.Errorf("source dir not accessible: %w", err)
}

Try / catch

if _, err := retireHookSidecar(op); err != nil {
	var pe *fs.PathError
	if errors.As(err, &pe) && errors.Is(pe.Err, os.ErrPermission) {
		// surface a permission-fix hint
	}
	return err
}

Prevention

When it happens

Trigger: During `bd migrate` apply, os.Stat(op.SourcePath) fails with an error other than os.ErrNotExist — e.g. the source sidecar's parent directory became inaccessible, or the path sits on a failed mount.

Common situations: Permissions on the source directory changed after validation passed; an NFS/removable mount dropped mid-run; security software blocked the stat.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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