gitbutlerapp/gitbutler · error · anyhow::Error
ProjectHandle payload must decode to an absolute filesystem
Error message
ProjectHandle payload must decode to an absolute filesystem path, got '{}' What it means
`ProjectHandle` encodes a repository location into a portable string payload. On decode, `encoded_str_to_path` base-decodes the payload and converts the bytes to a path via gix; a payload that decodes but is not an absolute path is rejected, because the handle must identify a workspace by absolute filesystem location.
Source
Thrown at crates/but-project-handle/src/project_handle.rs:112
}
impl TryFrom<ProjectHandle> for PathBuf {
type Error = anyhow::Error;
fn try_from(value: ProjectHandle) -> Result<Self, Self::Error> {
value.into_path()
}
}
fn encoded_str_to_path(encoded: &str) -> anyhow::Result<PathBuf> {
let bytes = decode(encoded)?;
let path = gix::path::try_from_byte_slice(&bytes)
.map_err(anyhow::Error::from)
.with_context(|| {
format!("Encoded ProjectHandle payload is not a valid filesystem path: '{encoded}'")
})?;
if !path.is_absolute() {
bail!(
"ProjectHandle payload must decode to an absolute filesystem path, got '{}'",
path.display()
);
}
Ok(path.to_owned())
}
fn path_to_string(path: &Path) -> Result<String, anyhow::Error> {
let bytes = gix::path::os_str_into_bstr(path.as_os_str())?;
Ok(encode(bytes))
}
fn encode(bytes: &[u8]) -> String {
URL_SAFE_NO_PAD.encode(bytes)
}
fn decode(encoded: &str) -> anyhow::Result<Vec<u8>> {
URL_SAFE_NO_PADView on GitHub (pinned to caf1f223d3)
Solutions
- Absolutize the path before encoding it into the handle (std::fs::canonicalize or std::path::absolute)
- Reject relative paths at the source (config loader, CLI parser) with a clear message
- Re-derive the handle from the repository's absolute workdir
Example fix
// before
let handle = ProjectHandle::from_path(Path::new("my-repo"))?; // relative -> bails on decode
// after
let abs = std::path::absolute(Path::new("my-repo"))?;
let handle = ProjectHandle::from_path(abs)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: only build handles from absolute paths
let abs = if path.is_absolute() {
path.to_path_buf()
} else {
std::path::absolute(path)?
};
let handle = ProjectHandle::from_path(abs)?; Type guard
// Rust
fn is_valid_project_path(p: &std::path::Path) -> bool {
p.is_absolute()
} Try / catch
Catch the decode error, re-derive the path from the repository's absolute workdir (e.g. via canonicalize), rebuild the handle, and retry once.
Prevention
- Always store absolute paths in config and databases; canonicalize user input at the boundary
- Reject relative paths in CLI/config parsers with an explicit message before they reach the handle
When it happens
Trigger: Creating or decoding a ProjectHandle whose payload encodes a relative path such as '.', '..', or 'my-repo' — typically a path captured with a different working directory or stored relative in config.
Common situations: Paths persisted from another machine or shell with a different cwd; config entries storing relative paths; tests and scripts using relative fixture paths.
Related errors
- PR template exists but must be valid UTF-8 text or markdown
- '{src}' is not a directory
- '{other}' is not a conflicted uncommitted file; `but resolve
- Refusing to read '{relative_path:?}' from commit {commit_id:
- Path to read from at '{}' isn't in the worktree directory '{
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/584dfd0060baae1c.
Report an issue: GitHub.