Affects the released 0.12.0 Windows build. Any /describe or /review fails, so the installed app is effectively unusable.
PermissionError: [Errno 13] Permission denied:
'C:\Program Files\Code Meeseeks\resources\pragent\python\Lib\site-packages\litellm\
litellm_core_utils\tokenizers\fb374d419588a4632f3f557e76b4b70aebbca790.<uuid>.tmp'
The traceback goes PRDescription.__init__ → TokenHandler → tiktoken.get_encoding("o200k_base") → read_file_cached → open(tmp, "wb").
Cause
Not a permissions setting — a bad file inside the package.
litellm points TIKTOKEN_CACHE_DIR at its own litellm_core_utils/tokenizers/ and ships encoding files there so tiktoken works offline. But the files it ships fail the expected_hash pinned by the tiktoken it depends on. Measured against litellm 1.99.0 / tiktoken 0.12.0:
| encoding |
shipped by litellm |
matches tiktoken''s pin |
o200k_base |
yes |
no |
cl100k_base |
yes |
no |
p50k_base |
yes |
no |
r50k_base |
no |
— |
tiktoken therefore treats the cache as invalid on every run: it deletes the file and re-downloads it into site-packages. Writable while building, read-only once installed under C:\Program Files — hence the crash.
Not model specific. The reported trace is a CLI provider (model='codex' → o200k_base), but a gpt model resolves through encoding_for_model() to the same stale files. Every path that counts tokens hits this.
Why it shipped
- A dev machine never shows it.
vendor/ is writable there, so tiktoken repairs itself on the first run and everything looks permanently fine.
- CI never showed it either. The build machine can also write, so the runtime assembled and smoke-tested clean — the stale file loads wherever it can be re-downloaded. "CI passed" proved nothing about the installed copy.
Same class as the pre-written .secrets.toml (already handled in the assembler): a dependency that writes under its own package at runtime. That one was fixed as a one-off without becoming a rule, which is why this recurred.
Fix
scripts/tiktoken-cache.py:
- prime (assemble time, before slimming) — repairs the bundled bytes so the cache is a hit and nothing is written at runtime;
- verify (smoke test, after slimming) — compares bundled bytes against tiktoken''s pinned hashes, so this cannot ship broken again; running after slimming also catches a slim rule that deletes the cache.
The assertion compares hashes rather than just loading an encoding, since loading is exactly what fails to discriminate here. Expected hashes are read from the installed tiktoken, never copied into our source, so they cannot drift on the next upgrade.
Verified end to end: restoring litellm''s stale copy makes verify fail; after prime, both encodings load from a genuinely read-only directory (write denied via icacls); putting the stale file back into that same read-only directory reproduces the reported PermissionError exactly.
The general rule is now recorded in AGENTS.md and docs/arch/02-agent/05-pragent-runtime.md.
Fix release
Ships in 0.12.1.
Affects the released 0.12.0 Windows build. Any
/describeor/reviewfails, so the installed app is effectively unusable.The traceback goes
PRDescription.__init__→TokenHandler→tiktoken.get_encoding("o200k_base")→read_file_cached→open(tmp, "wb").Cause
Not a permissions setting — a bad file inside the package.
litellm points
TIKTOKEN_CACHE_DIRat its ownlitellm_core_utils/tokenizers/and ships encoding files there so tiktoken works offline. But the files it ships fail theexpected_hashpinned by the tiktoken it depends on. Measured against litellm 1.99.0 / tiktoken 0.12.0:o200k_basecl100k_basep50k_baser50k_basetiktoken therefore treats the cache as invalid on every run: it deletes the file and re-downloads it into
site-packages. Writable while building, read-only once installed underC:\Program Files— hence the crash.Not model specific. The reported trace is a CLI provider (
model='codex'→o200k_base), but agptmodel resolves throughencoding_for_model()to the same stale files. Every path that counts tokens hits this.Why it shipped
vendor/is writable there, so tiktoken repairs itself on the first run and everything looks permanently fine.Same class as the pre-written
.secrets.toml(already handled in the assembler): a dependency that writes under its own package at runtime. That one was fixed as a one-off without becoming a rule, which is why this recurred.Fix
scripts/tiktoken-cache.py:The assertion compares hashes rather than just loading an encoding, since loading is exactly what fails to discriminate here. Expected hashes are read from the installed tiktoken, never copied into our source, so they cannot drift on the next upgrade.
Verified end to end: restoring litellm''s stale copy makes
verifyfail; afterprime, both encodings load from a genuinely read-only directory (write denied viaicacls); putting the stale file back into that same read-only directory reproduces the reportedPermissionErrorexactly.The general rule is now recorded in AGENTS.md and
docs/arch/02-agent/05-pragent-runtime.md.Fix release
Ships in 0.12.1.