vercel/turborepo · critical
failed to calculate Turbo hash: {err}
Error message
failed to calculate Turbo hash: {err} What it means
turborepo-hash implements a capnproto-based Hashable trait: try_hash serializes the message and xxh64-hashes its first segment, returning an error when the capnp "message is not canonical". The convenience hash() converts any such error into a panic ("failed to calculate Turbo hash"), so this is an internal invariant failure inside turbo's task hashing, not a caller-configurable condition.
Source
Thrown at crates/turborepo-hash/src/traits.rs:30
fn try_hash(self) -> Result<String, Error> {
let message = self.into_builder()?;
debug_assert_eq!(
message.get_segments_for_output().len(),
1,
"message is not canonical"
);
let buf = message.get_segments_for_output()[0];
let out = xxhash_rust::xxh64::xxh64(buf, 0);
Ok(hex::encode(out.to_be_bytes()))
}
fn hash(self) -> String {
self.try_hash()
.unwrap_or_else(|err| panic!("failed to calculate Turbo hash: {err}"))
}
}
View on GitHub (pinned to f9245100cf)
Solutions
- Upgrade turborepo — known serialization bugs are fixed in patches
- Clear the local turbo cache and .turbo directories, then retry
- If it reproduces, minimize the turbo.json/workspace setup and file an issue
- In downstream Rust code, call try_hash() instead of hash() to get a Result
Example fix
// before
let hash = item.hash(); // panics on non-canonical message
// after
match item.try_hash() {
Ok(hash) => { /* use hash */ }
Err(err) => { /* degrade gracefully: skip caching, log */ }
} Defensive patterns
Strategy: fallback
Validate before calling
// Prefer the Result-returning API in downstream Rust code
match hashable.try_hash() {
Ok(h) => use_hash(h),
Err(e) => {
tracing::warn!("hash failed, skipping cache: {e}");
return None;
}
} Try / catch
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| item.hash()))
.map_err(|p| {
let msg = p
.downcast_ref::<&str>()
.map(|s| s.to_string())
.unwrap_or_else(|| "hash panic".into());
msg
})
.and_then(|h| Ok(h)) Prevention
- Pin a known-good turborepo version; upgrade deliberately rather than floating
- Keep hashing inside the turbo process boundary so a panic cannot take down your host application
- In Rust code, never call hash() on untrusted/unvalidated Hashable inputs — use try_hash()
When it happens
Trigger: Hashing inputs whose capnp serialization is non-canonical — an internal API misuse or a serialization bug in the caller building the message; effectively unreachable from JavaScript/TypeScript surfaces, it aborts the turbo process.
Common situations: Seen inside `turbo run` after upgrading across serialization changes, with unusual workspace/task configurations, or with corrupted in-memory state; never triggered by config files alone.
Related errors
- Unable to encode '{s}'
- joined path is absolute and valid utf8: {err:?}
- collapsed path should be absolute: {err:?}
- clean should produce valid UTF-8: {err:?}
- anchored system path is relative: {}
AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17).
Data as JSON: /api/errors/a4462c856deaa537.
Report an issue: GitHub.