gastownhall/beads · error

%s %q is not an absolute native path

Error message

%s %q is not an absolute native path

What it means

cleanAbsoluteUserDirectory validates that a resolved user-directory candidate is an absolute, native (non-MSYS/POSIX-style) path before it can be used for filesystem APIs. It throws when filepath.Clean produces a relative path, meaning the underlying resolution (e.g. HOME or USERPROFILE) yielded something non-absolute. This guards user config.yaml resolution from silently using mangled directory roots.

Source

Thrown at internal/config/user_config_path.go:55

		candidates.documented = filepath.Clean(filepath.Join(home, ".config", "bd", "config.yaml"))
	}

	if nativeDir, err := cleanAbsoluteUserDirectory("native user config directory", nativeConfigDir, nativeErr); err != nil {
		candidates.nativeErr = err
	} else {
		candidates.native = filepath.Clean(filepath.Join(nativeDir, "bd", "config.yaml"))
	}

	return candidates
}

func cleanAbsoluteUserDirectory(label, path string, resolutionErr error) (string, error) {
	if resolutionErr != nil {
		return "", fmt.Errorf("%s: %w", label, resolutionErr)
	}
	cleaned := filepath.Clean(path)
	if !filepath.IsAbs(cleaned) {
		return "", fmt.Errorf("%s %q is not an absolute native path", label, path)
	}
	return cleaned, nil
}

// UserConfigYamlPath resolves the user-level config.yaml to a cleaned,
// absolute path suitable for native filesystem APIs. It prefers the documented
// <home>/.config/bd location when that file exists, then an existing native
// os.UserConfigDir location. For a new file it keeps the documented location
// as the creation target when possible, falling back to the native location
// only when the home directory itself cannot be resolved safely.
func UserConfigYamlPath() (string, error) {
	return selectUserConfigYamlPath(currentUserConfigYamlCandidates())
}

func selectUserConfigYamlPath(candidates userConfigYamlCandidates) (string, error) {
	if userConfigPathExists(candidates.documented) {
		return candidates.documented, nil
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the environment variable: set HOME (or USERPROFILE on Windows) to a fully qualified native absolute path (e.g. C:\Users\name, not /c/Users/name).
  2. Unset the MSYS/MSYS2 path translation (e.g. run from cmd/PowerShell instead of Git Bash, or unset MSYS overrides).
  3. If a custom home override is intended, pass an absolute path when invoking bd.
  4. Upgrade bd: newer versions reject MSYS roots with a clearer label naming which candidate failed.

Example fix

// before (Git Bash on Windows)
export HOME=/c/Users/alice
bd ready
// after
export HOME='C:\Users\alice'
bd ready
Defensive patterns

Strategy: validation

Validate before calling

home := os.Getenv("HOME") // or USERPROFILE on Windows
if home == "" || !filepath.IsAbs(filepath.Clean(home)) {
    return fmt.Errorf("HOME must be an absolute native path, got %q", home)
}

Type guard

func isAbsoluteNativePath(p string) bool {
    return p != "" && filepath.IsAbs(filepath.Clean(p))
}

Prevention

When it happens

Trigger: Calling UserConfigYamlPath / buildUserConfigYamlCandidates when the resolved home directory variable (HOME, USERPROFILE) is set to a relative path like 'foo' or an MSYS-style root like '/c/Users' on Windows, so filepath.IsAbs fails after Clean.

Common situations: Developers on Windows running bd inside Git Bash/MSYS where HOME=/c/Users/name leaks into the Go process; CI containers with HOME set to a relative path; shell profiles exporting a tilde or relative HOME.

Related errors


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