Skip to content

fix(docker): CPU inference broken by unpinned torch; root-owned ~/.cache#945

Open
thiagomargatho wants to merge 2 commits into
jamiepine:mainfrom
thiagomargatho:fix/docker-cpu-inference
Open

fix(docker): CPU inference broken by unpinned torch; root-owned ~/.cache#945
thiagomargatho wants to merge 2 commits into
jamiepine:mainfrom
thiagomargatho:fix/docker-cpu-inference

Conversation

@thiagomargatho

@thiagomargatho thiagomargatho commented Jul 22, 2026

Copy link
Copy Markdown

Summary

Two independent Docker fixes, found while running the CPU image in production for ~a week:

1. CPU builds: pin torch 2.7.1 (unpinned torch → 2.13 → CPU inference broken)

With torch>=2.2.0 unpinned, pip resolves the latest release. On torch 2.13 CPU inference fails in every engine we tested:

  • Kokoro / LuxTTS: Cannot copy out of meta tensor; no data!
  • Qwen3-TTS: unsupported scalarType inside torch.autocast

2.7.1 is the newest version that works, and it matches hume-tada's declared range (torch>=2.7,<2.8 — currently unenforced since it's installed with --no-deps).

The pin lives in the Dockerfile's CPU branch (the else of the existing ROCm conditional), not in requirements.txt, so ROCm builds keep resolving torch from the ROCm wheel index for both ROCM_VERSION=6.3 and 7.2 — a hard pin in requirements would have no matching wheel on the 7.2 index.

Qwen3-TTS is now installed with --no-deps (same as chatterbox-tts and hume-tada) so its dependency list can't re-resolve torch/transformers and silently undo the pin.

2. Entrypoint: chown ~/.cache (root-owned on every container create)

Docker creates /home/voicebox/.cache — the parent of the huggingface-cache volume mountpoint — as root on every container create, and a fresh named volume is root-owned too. The app runs as voicebox (uid 999), so any cache write outside the HF mount (torch hub, spacy, …) fails with Permission denied, and on a fresh volume even HF model downloads fail.

The entrypoint already runs as root before gosu, so a non-recursive mkdir -p + chown there fixes both cases at zero cost.

Testing

  • CPU image built from scratch and run in production (Compose, named volumes): Kokoro, LuxTTS and Qwen3-TTS all generate correctly on torch 2.7.1; all fail on 2.13 with the errors above.
  • Container recreated from a clean state: ~/.cache and the HF mountpoint come up owned by voicebox, writable by uid 999.
  • ROCm path untouched by the cache fix's placement in the shared entrypoint (chown is filesystem-only, runs before the existing GPU group logic's gosu).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved CPU container builds by consistently installing compatible, pinned PyTorch versions.
    • Prevented later package installations from overriding the selected PyTorch version.
    • Fixed runtime access to Hugging Face model and tokenizer caches by creating the cache directory with appropriate permissions.

thiagomargatho and others added 2 commits July 22, 2026 08:40
Unpinned torch resolves to the latest release (2.13 at the time of
writing), which breaks CPU inference in every engine tested:
- Kokoro/LuxTTS: "Cannot copy out of meta tensor; no data!"
- Qwen3-TTS: "unsupported scalarType" inside torch.autocast

2.7.1 is the newest version that works and matches hume-tada's
declared range (torch>=2.7,<2.8). Pinned in the Dockerfile's CPU
branch rather than requirements.txt so ROCm builds keep resolving
torch from the ROCm wheel index untouched.

Qwen3-TTS is now installed with --no-deps (like chatterbox-tts and
hume-tada already are) so its dependency list can't re-resolve
torch/transformers and undo the pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Docker creates /home/voicebox/.cache (parent of the huggingface-cache
volume mountpoint) owned by root on every container create, and a
fresh named volume is root-owned too. The app runs as the voicebox
user (uid 999), so anything that writes a cache outside the HF mount
(torch hub, spacy, ...) fails with Permission denied.

The entrypoint already runs as root before dropping privileges via
gosu — create/chown the cache dirs there (non-recursive, instant).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Dockerfile adds pinned CPU PyTorch installation and preserves those versions during later package installs. The ROCm entrypoint creates the Hugging Face cache directory and assigns it to the application user.

Changes

Container runtime updates

Layer / File(s) Summary
CPU PyTorch installation
Dockerfile
The non-ROCm path installs torch==2.7.1 and torchaudio==2.7.1; later --no-deps installs avoid re-resolving these packages.
Hugging Face cache setup
scripts/rocm-entrypoint.sh
Startup creates /home/voicebox/.cache/huggingface and assigns ownership of the cache directories to voicebox.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the two main Docker fixes: pinning CPU Torch to restore inference and fixing root-owned cache permissions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Dockerfile`:
- Around line 58-65: Update the CPU installation command in the Dockerfile’s
torch/torchaudio fallback branch to use the PyTorch CPU wheel index at
https://download.pytorch.org/whl/cpu while preserving the existing pinned
versions and installation prefix.

In `@scripts/rocm-entrypoint.sh`:
- Around line 15-20: Update the cache ownership setup around mkdir and chown to
recursively repair ownership of all existing descendants under
/home/voicebox/.cache/huggingface, while retaining ownership correction for the
parent cache directory. Ensure reused volumes with root-owned files and
subdirectories become writable by voicebox.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: df8a33a9-33cf-4357-8eb3-3fb8244c6677

📥 Commits

Reviewing files that changed from the base of the PR and between 52f8d8d and d2b3057.

📒 Files selected for processing (2)
  • Dockerfile
  • scripts/rocm-entrypoint.sh

Comment thread Dockerfile
Comment on lines +58 to +65
else \
pip install --no-cache-dir --prefix=/install torch==2.7.1 torchaudio==2.7.1; \
fi
# ^ CPU builds pin torch: 2.8+ breaks CPU inference in every engine tested
# (Kokoro/LuxTTS: "Cannot copy out of meta tensor"; Qwen: "unsupported
# scalarType" in torch.autocast). 2.7.1 is the newest that works and matches
# hume-tada's torch>=2.7,<2.8. Installed before requirements.txt so the open
# torch range there keeps this version instead of resolving to latest.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

echo '--- Dockerfile context ---'
nl -ba Dockerfile | sed -n '45,80p'

echo
echo '--- Search for torch install patterns ---'
rg -n "torch==|torchaudio==|download.pytorch.org|cpu" Dockerfile requirements*.txt pyproject.toml . || true

Repository: jamiepine/voicebox

Length of output: 223


🏁 Script executed:

set -euo pipefail

echo '--- Dockerfile context ---'
sed -n '45,80p' Dockerfile | cat -n

echo
echo '--- Search for torch install patterns ---'
rg -n "torch==|torchaudio==|download.pytorch.org|cpu" Dockerfile requirements*.txt pyproject.toml . || true

Repository: jamiepine/voicebox

Length of output: 50374


🌐 Web query:

PyTorch 2.7.1 pip install default index CPU wheel torch torchaudio documentation

💡 Result:

To install the CPU-only version of PyTorch 2.7.1, you should use the official PyTorch wheel index to ensure the correct CPU-only binaries are fetched [1][2]. Use the following pip command: pip install torch==2.7.1 torchvision==0.22.1 torchaudio==2.7.1 --index-url https://download.pytorch.org/whl/cpu Key details for this installation: 1. Index URL: It is important to use the --index-url flag with https://download.pytorch.org/whl/cpu. Using --find-links (-f) or omitting the index URL can lead to unintended installations of CUDA-enabled dependencies [2]. 2. Version Compatibility: The command above includes the matching versions of torchvision and torchaudio that were typically released alongside PyTorch 2.7.1 [1]. 3. Official Documentation: While PyTorch 2.13 is the current version as of July 2026 [3][4], specific installation instructions for historical versions like 2.7.1 are maintained in the official Previous PyTorch Versions documentation [1]. You can access general documentation for PyTorch at https://docs.pytorch.org/docs/stable/index.html [5].

Citations:


Use the CPU wheel index here.

torch==2.7.1 / torchaudio==2.7.1 for the CPU image should come from https://download.pytorch.org/whl/cpu; the plain default index can resolve the wrong wheel set.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile` around lines 58 - 65, Update the CPU installation command in the
Dockerfile’s torch/torchaudio fallback branch to use the PyTorch CPU wheel index
at https://download.pytorch.org/whl/cpu while preserving the existing pinned
versions and installation prefix.

Comment on lines +15 to +20
# Docker creates the HF volume mountpoint's parent (~/.cache) as root on every
# container create, and a fresh volume is root-owned too — without this the app
# user can't write any cache (torch, spacy) outside the HF mount.
mkdir -p /home/voicebox/.cache/huggingface
chown voicebox:voicebox /home/voicebox/.cache /home/voicebox/.cache/huggingface

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Fix ownership of existing cache contents.

The persistent huggingface-cache volume can already contain root-owned hub subdirectories and files. This non-recursive chown changes only the two directory entries, so voicebox may still fail when updating an existing cache after an upgrade or reused volume. Apply a one-time recursive ownership migration, or otherwise repair all existing descendants.

Proposed fix
 mkdir -p /home/voicebox/.cache/huggingface
-chown voicebox:voicebox /home/voicebox/.cache /home/voicebox/.cache/huggingface
+chown -R voicebox:voicebox /home/voicebox/.cache
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Docker creates the HF volume mountpoint's parent (~/.cache) as root on every
# container create, and a fresh volume is root-owned too — without this the app
# user can't write any cache (torch, spacy) outside the HF mount.
mkdir -p /home/voicebox/.cache/huggingface
chown voicebox:voicebox /home/voicebox/.cache /home/voicebox/.cache/huggingface
# Docker creates the HF volume mountpoint's parent (~/.cache) as root on every
# container create, and a fresh volume is root-owned too — without this the app
# user can't write any cache (torch, spacy) outside the HF mount.
mkdir -p /home/voicebox/.cache/huggingface
chown -R voicebox:voicebox /home/voicebox/.cache
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/rocm-entrypoint.sh` around lines 15 - 20, Update the cache ownership
setup around mkdir and chown to recursively repair ownership of all existing
descendants under /home/voicebox/.cache/huggingface, while retaining ownership
correction for the parent cache directory. Ensure reused volumes with root-owned
files and subdirectories become writable by voicebox.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant