cf deploy: Python Workers fail with 'No module named workers' because vendored modules are uploaded as ./python_modules/...
Los mantenedores suelen responder en 1 día
Ya se ha fusionado un pull request relacionado.
- #393 de @MattieTK — fusionado
Evaluación
- Dificultad
- 2/5
- Tiempo estimado
- 1-3 horas
- Aptitud para principiantes
- 76/100
- Tipo de issue
- Error
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- python, typescript
Línea de trabajo
El issue señala el bucle de carga de módulos en el bundle publicado dist/deploy-input-*.mjs; localiza su código fuente en el repositorio y comprueba si las pruebas cubren los nombres de los módulos cargados. Compara los nombres que envía cf deploy con las claves del manifiesto y con el comportamiento de Wrangler que aquí se describe como funcional. Se considera terminado cuando un Worker de Python puede importar el SDK workers vendorizado después del deploy; comprueba también que el ejemplo de Rust siga desplegándose.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Summary of the issue
After migrating a working pywrangler project with cf migrate, cf deploy fails for Python Workers that import the Workers SDK (from workers import ...).
The migration itself works. cf migrate reports no follow-ups and writes a correct cloudflare.config.ts (python_workers flag, src/entry.py entrypoint), and cf deploy then builds the project with the same modules as Wrangler. The failure comes at upload: the version is rejected with 10021 ModuleNotFoundError: No module named 'workers'. The same project deploys fine with pywrangler deploy. The bug is in how cf deploy names modules in the upload, not in the migration or the config.
Root cause: cf deploy uploads every non-entrypoint module as ./<path>, where Wrangler uploads <path>. Python Workers' vendored packages must be named python_modules/...; as ./python_modules/..., the runtime doesn't add them to site-packages, so the external workers SDK (workers-runtime-sdk, vendored by pywrangler sync) can't be imported.
I captured both tools' uploads against a local fake API (CLOUDFLARE_API_BASE_URL). Both send PUT /accounts/:id/workers/scripts/:name, and the parts have identical content, sizes and content types. The only meaningful difference is the part names:
| Wrangler / pywrangler (works) | cf (fails) | |
|---|---|---|
| main module | entry.py |
entry.py |
| vendored SDK | python_modules/workers/__init__.py |
./python_modules/workers/__init__.py |
| other vendored files | python_modules/_workers_sdk_patch_loader.pth, ... |
./python_modules/_workers_sdk_patch_loader.pth, ... |
The Build Output manifest (.cloudflare/output/v0/workers/default/worker.config.json) is correct: its keys are python_modules/... without a prefix. The ./ is added when cf deploy turns the manifest into upload modules. In the published 1.0.0-beta.20 bundle (dist/deploy-input-*.mjs, de-minified):
for (const [name, mod] of Object.entries(manifest.modules)) {
if (name === mainModule) continue;
// ...
modules.push({ name: `./${name}`, filePath, content, type: moduleTypes[mod.type] });
}
Proposed fix: use the manifest key as the module name, as Wrangler does:
- modules.push({ name: `./${name}`, filePath, content, type: moduleTypes[mod.type] });
+ modules.push({ name, filePath, content, type: moduleTypes[mod.type] });
I verified this by making that one-line change in a local copy of cf 1.0.0-beta.20 and deploying for real:
| Worker | Unpatched cf | Patched cf |
|---|---|---|
Python hello world (vendored workers SDK) |
400, 10021 No module named 'workers' |
Deployed; GET / returns 200 Hello from a Python Worker |
Rust hello world (worker-build, Wasm + JS shim) |
Deployed, 200 | Deployed; GET / returns 200 Hello from a Rust Worker (no regression) |
Not tested: a JS/TS Worker with additional modules, and Python Workers with third-party packages beyond the SDK. If the ./ is needed for JS in some case, a narrower fix is to skip the prefix for python_modules/ paths only. I'm happy to open a PR with the fix and a test if that would help.
Related: #56 covers Python support in cf dev. This issue is about cf deploy, which otherwise already handles Python projects that pywrangler sync has prepared.
Not platform-specific: the prefix is a hard-coded string. I reproduced the same upload names on Linux (WSL2, Ubuntu 22.04, Node 24.22.1): 32 of 33 module parts are ./-prefixed, with only the entrypoint unprefixed.
Expected behaviour
cf deploy uploads a Python Worker with vendored packages the same way pywrangler deploy does, with module names exactly as in the Build Output manifest, and the Worker can import the workers SDK.
Version of cf used
1.0.0-beta.20
System information and package versions
System:
OS: Windows 11 10.0.26200
CPU: (24) x64 12th Gen Intel(R) Core(TM) i9-12900F
Memory: 22.58 GB / 63.82 GB
Binaries:
Node: 22.21.1 - %USERPROFILE%\AppData\Local\Volta\tools\image\node\22.21.1\node.EXE
npm: 10.9.4 - %USERPROFILE%\AppData\Local\Volta\tools\image\node\22.21.1\npm.CMD
bun: 1.3.5 - %USERPROFILE%\.bun\bin\bun.EXE
npmPackages:
cf: ^1.0.0-beta.20 => 1.0.0-beta.20
wrangler: 4.152.0 => 4.152.0
Also: workers-py (pywrangler) 1.17.8, vendored workers-runtime-sdk 1.9.5, uv 0.13.5. Reproduced on Linux as described above.
Reproduction (optional)
src/entry.py:
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
return Response("Hello from a Python Worker")
wrangler.jsonc:
{
"name": "cf-python-repro",
"main": "src/entry.py",
"compatibility_date": "2026-10-01",
"compatibility_flags": ["python_workers"]
}
pyproject.toml: dependencies = [], dev dependency group ["workers-py", "workers-runtime-sdk"]. package.json: devDependency [email protected].
npm install
uv run pywrangler sync # populates python_modules/ (workers SDK 1.9.5 + helpers)
cf migrate # "Migration complete", no follow-up items
cf deploy # builds 32 modules (111.15 KiB vendored), then fails with 10021
Control: with the same files, deleting .cloudflare/output and running uv run pywrangler deploy succeeds, and the Worker returns 200 Hello from a Python Worker.
Side note: after any cf build/cf deploy, wrangler deploy refuses to run until .cloudflare/output is deleted ("Cloudflare Build Output was found at .cloudflare/output"). That's a reasonable safeguard, but combined with this bug, Python users who fall back to pywrangler hit it straight away.
Relevant error logs (optional)
[10021] Uncaught Error: PythonError: Traceback (most recent call last):
File "/lib/python314.zip/_pyodide/_base.py", line 523, in eval_code
File "/lib/python314.zip/_pyodide/_base.py", line 357, in run
File "<exec>", line 9, in <module>
File "/lib/python314.zip/_pyodide/_base.py", line 666, in pyimport_impl
File "/session/metadata/entry.py", line 1, in <module>
from workers import Response, WorkerEntrypoint
File "/lib/python3.14/site-packages/workers/__init__.py", line 3, in <module>
ModuleNotFoundError: No module named 'workers'
You need to update to workers-py >= 1.9 or to pass disable_python_external_sdk
[code: 10021]
400 Bad Request
(The "update to workers-py >= 1.9" hint is misleading here: workers-py 1.17.8 is installed, and the same python_modules/ deploys fine through pywrangler.)
- Lenguaje dominante
- TypeScript
- Estrellas
- 916
- Forks
- 53
- Merge medio
- 18 h 37 min
- PR fusionados (30 d)
- 197
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de cloudflare/cf
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
cloudflare/cf#344 ·
Los mantenedores suelen responder en 1 día
-
upstream
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
cloudflare/cf#262 ·
Los mantenedores suelen responder en 1 día
-
`cf dev` rejects `--port` and `--host` for Vite projects, including the `cf init` templatePosiblemente ocupada @jamesopstad la tomó hace 11 días. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
cloudflare/cf#223 · 2 asignados ·
Los mantenedores suelen responder en 1 día
-
upstream
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
cloudflare/cf#179 ·
Los mantenedores suelen responder en 1 día
-
`cf workers …` API commands fail without workerd: workers module statically imports miniflareAbierto
Dificultad 3/5 1-2 días Aptitud para principiantes 72/100
cloudflare/cf#390 ·
Los mantenedores suelen responder en 1 día
Todos los issues de cloudflare/cf
Issues similares
-
area:desktop bug documentation
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
anthropics/claude-code#104801 ·
Los mantenedores suelen responder en 1 día
-
Add: Halloween Non Stop SDAbiertocheck:passed streams:add
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
Los mantenedores suelen responder en 2 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
spudly/design-system#110 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
Los mantenedores suelen responder en 1 día
-
[Bug]: REST API URL starting with "http" but no scheme (e.g. httpbin.org/get) is not given an http:// prefixPosiblemente ocupada @ItsDeadlyProgrammer la tomó hoy. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 68/100
appsmithorg/appsmith#42471 · 1 comentario ·
Los mantenedores suelen responder en 2 días