⚠️ Note: This issue was investigated and drafted with AI assistance (GitHub Copilot). The reproducer below has been executed and the failure was confirmed locally.
Summary
Since 0.11.9 (PR #19201, "Remove our dependency on nanoid"), uv fails with invalid ID: "<id>" (must be 16 ID characters in the alphabet) when it encounters cache entries that were written by an older uv version. Older uv used nanoid with a 21-character token; the new uv-fastid deserializer strictly requires exactly 16 characters, so any pre-existing 21-character ID on disk now causes a hard failure instead of a cache miss.
The cache bucket version was intentionally not bumped in #19201, so existing caches on shared/CI workers are effectively poisoned after upgrading to 0.11.9 / 0.11.10.
Reproduction
Self-contained shell reproducer (only requires python3 + network for pip):
#!/usr/bin/env bash
# Reproducer for uv 0.11.9/0.11.10 regression:
# "Failed to deserialize cache entry: invalid ID ... (must be 16 ID characters in the alphabet)"
set -euo pipefail
WORK="$(mktemp -d)"
echo "Workdir: $WORK"
cd "$WORK"
export UV_CACHE_DIR="$WORK/uv-cache"
mkdir -p "$UV_CACHE_DIR"
mkdir -p pkg/src/dummy_pkg
cat > pkg/pyproject.toml <<'EOF'
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
[project]
name = "dummy-pkg"
version = "0.0.1"
EOF
: > pkg/src/dummy_pkg/__init__.py
python3 -m venv pkgbuild-venv
./pkgbuild-venv/bin/pip install -q build
./pkgbuild-venv/bin/python -m build --sdist --outdir dist pkg >/dev/null
SDIST="$(ls "$WORK"/dist/*.tar.gz)"
install_uv() {
python3 -m venv "$2"
"$2/bin/pip" install -q "uv==$1"
}
echo "=== Step 1: prime cache with uv 0.11.8 ==="
install_uv 0.11.8 "$WORK/uv-old"
python3 -m venv "$WORK/target-venv"
"$WORK/uv-old/bin/uv" pip install \
--python "$WORK/target-venv/bin/python" \
--reinstall --no-deps "$SDIST"
echo "=== Step 2: inspect IDs in the cache ==="
find "$UV_CACHE_DIR" -maxdepth 4 -type d -name 'archive-*' -print -exec sh -c '
ls "$1" | head -n 5 | while read -r name; do
printf " %s (len=%d)\n" "$name" "${#name}"
done
' _ {} \;
echo "=== Step 3: rerun with uv 0.11.10 against the SAME cache ==="
install_uv 0.11.10 "$WORK/uv-new"
"$WORK/uv-new/bin/uv" pip install \
--python "$WORK/target-venv/bin/python" \
--reinstall --no-deps "$SDIST"
Observed output
=== Step 2: inspect IDs in the cache ===
/tmp/tmp.SA4yr9SC6n/uv-cache/archive-v0
SzRiWVFFInsNaf0g33NFd (len=21)
UKJkCZ3IOEXWTD5T0Le59 (len=21)
=== Step 3: rerun with uv 0.11.10 against the SAME cache ===
uv 0.11.10 (x86_64-unknown-linux-gnu)
Using Python 3.14.4 environment at: target-venv
× Failed to build `dummy-pkg @
│ file:///tmp/tmp.SA4yr9SC6n/dist/dummy_pkg-0.0.1.tar.gz`
├─▶ Failed to deserialize cache entry
╰─▶ invalid ID: "HM0NxJml5hc7UjbfTWT1r" (must be 16 ID characters in the
alphabet)
The failing ID is exactly 21 characters — the old nanoid length. Note also that during the priming step uv 0.11.10 already prints WARNING: Cache entry deserialization failed, entry ignored for some entries, suggesting there is already a graceful-degrade path elsewhere in the codebase that the failing call site does not use.
Expected behavior
Unrecognized/legacy ID formats should be treated as a cache miss (or be ignored / migrated), not aborted with a hard error — consistent with the discussion on #19201 where bumping the bucket was considered acceptable specifically to avoid this class of failure.
Original CI failure (real-world trigger)
× Failed to build `voraus-release-test @ file:///.../voraus_release_test-2.25.1.dev8+g5bd0c2738.tar.gz`
├─▶ Failed to deserialize cache entry
╰─▶ invalid ID: "gtl3Kss14gljY4ur63X_i" (must be 16 ID characters in the alphabet)
Triggered via tox-uv ~=1.29.0 (which pulls uv<1,>=0.9.1) on a long-lived Jenkins agent whose cache was previously populated by uv ≤ 0.11.8.
Platform
Linux (Debian-based Jenkins build agent and reproduced locally on Linux x86_64), Python 3.11 / 3.14.
Version
Broken: uv 0.11.9, uv 0.11.10
Last good: uv 0.11.8
Summary
Since 0.11.9 (PR #19201, "Remove our dependency on nanoid"), uv fails with
invalid ID: "<id>" (must be 16 ID characters in the alphabet)when it encounters cache entries that were written by an older uv version. Older uv usednanoidwith a 21-character token; the newuv-fastiddeserializer strictly requires exactly 16 characters, so any pre-existing 21-character ID on disk now causes a hard failure instead of a cache miss.The cache bucket version was intentionally not bumped in #19201, so existing caches on shared/CI workers are effectively poisoned after upgrading to 0.11.9 / 0.11.10.
Reproduction
Self-contained shell reproducer (only requires
python3+ network for pip):Observed output
The failing ID is exactly 21 characters — the old
nanoidlength. Note also that during the priming step uv 0.11.10 already printsWARNING: Cache entry deserialization failed, entry ignoredfor some entries, suggesting there is already a graceful-degrade path elsewhere in the codebase that the failing call site does not use.Expected behavior
Unrecognized/legacy ID formats should be treated as a cache miss (or be ignored / migrated), not aborted with a hard error — consistent with the discussion on #19201 where bumping the bucket was considered acceptable specifically to avoid this class of failure.
Original CI failure (real-world trigger)
Triggered via
tox-uv ~=1.29.0(which pullsuv<1,>=0.9.1) on a long-lived Jenkins agent whose cache was previously populated by uv ≤ 0.11.8.Platform
Linux (Debian-based Jenkins build agent and reproduced locally on Linux x86_64), Python 3.11 / 3.14.
Version