Docs menu

Troubleshooting Python

Common build and runtime errors for Python apps on Primcloud, with the fix for each.

On this page

Two places to look when a deploy misbehaves:

  • Build log: the Deployments tab streams the full output from the Python build: version resolution, pip/Poetry/uv install output, and collectstatic output for Django apps.
  • Runtime log: the Logs tab streams stdout and stderr from your running pods. Gunicorn startup errors, unhandled exceptions, and import errors show up here.

This page lists the errors that come up most often, in the order they'd typically bite you: detection, version resolution, environment checks, dependency install, then runtime.

Common build errors#

Couldn't find any supported Python package manager files#

The build looked for requirements.txt, poetry.lock, or uv.lock at the repo root and found none.

Fix. Add one of them at the root:

  • pip: commit a requirements.txt (an empty file is fine if you have no dependencies).
  • Poetry: run poetry lock locally and commit poetry.lock.
  • uv: run uv lock locally and commit uv.lock (uv also requires .python-version).

Check the file is at the top level of the repo, spelled exactly (case-sensitive), and not excluded by .gitignore.

Multiple Python package manager files were found#

More than one of requirements.txt, poetry.lock, uv.lock is present at the root.

Fix. Pick one package manager and delete the others. If you're migrating from pip to Poetry or uv, drop requirements.txt in the same commit that adds the new lockfile.

Pipfile detected, but not supported#

The build sees Pipfile / Pipfile.lock at the root but doesn't have a Pipenv install path.

Fix. Migrate to pip, Poetry, or uv. Simplest option: pipenv requirements > requirements.txt and commit that instead. Longer-term: run uv init or poetry init and adopt one of the lockfile-driven managers.

The runtime.txt file isn't supported#

The build reads .python-version and doesn't read runtime.txt.

Fix. Delete runtime.txt. Create .python-version at the repo root with your major Python version:

.python-version
3.14

No python- prefix, no quotes, no .txt extension.

Invalid Python version in .python-version#

The file exists but doesn't parse: bad format, multiple versions, a python- prefix, or an unrecognized version string.

Fix. Write one bare version per file, either major-only (recommended) or an exact X.Y.Z patch. Comments must start with #.

No Python version was specified (uv)#

uv builds require .python-version. It's not optional the way it is for pip and Poetry.

Fix. Run uv python pin 3.14 (adjust to your major), commit the generated .python-version, and redeploy.

The requested Python version has reached end-of-life#

The version you pinned is EOL upstream and no longer in the Primcloud Runtime.

Fix. Bump .python-version to a supported major; see Runtime versions for the list. Run your test suite locally against the new version before deploying.

The requested Python version isn't recognised#

The version you pinned doesn't map to anything the Primcloud Runtime ships: either a typo, an unreleased version, or a major beyond the current supported range.

Fix. Check against Runtime versions and set .python-version to a supported major.

Unsafe environment variable#

The build rejects a small set of environment variables that would break the install: VIRTUAL_ENV, PYTHONHOME, PIP_TARGET, PIP_PREFIX, PIP_USER, POETRY_HOME, POETRY_VIRTUALENVS_CREATE, UV_PROJECT_ENVIRONMENT, UV_PYTHON, and similar variables that control where Python or the package manager installs things. If one is set on your app, the build fails immediately with a list of the offending vars.

Fix. Remove those variables from the Secrets panel. If you didn't set them yourself, check that a build hook or a container base image isn't setting them.

pip install / poetry sync / uv sync failed#

The package manager exited non-zero. The actual error is in the build log directly above Primcloud's own error message: a missing package, a version conflict, a native build that couldn't find a header file, and so on.

Fix. Read the package manager's error and address it:

  • Version conflict: pin compatible versions in requirements.txt / pyproject.toml and re-lock.
  • Missing header (fatal error: X.h: No such file or directory): declare the corresponding -dev package in project.toml (see Customizing the build → Debian packages). For example, psycopg2 needs libpq-dev; lxml from source needs libxml2-dev and libxslt1-dev.
  • Missing wheel for the Python version: either upgrade the package to a version that publishes wheels for your Python, or downgrade .python-version to one the wheel supports.

Reproduce locally with the same command the build runs; see Package managers → Install behavior for each.

Django collectstatic failed#

collectstatic ran because Django is installed and manage.py is present, but it exited non-zero.

Fix. The Django error is in the build log. Common causes:

  • Settings module can't import. A missing env var read at import time (a DATABASE_URL, SECRET_KEY, or similar). Either provide a build-time default in settings.py or set the variable in the Secrets panel.
  • STATIC_ROOT not set. Set STATIC_ROOT in settings.py to a path Django can write to during the build, typically BASE_DIR / "staticfiles".
  • django.contrib.staticfiles not enabled. If your app doesn't serve static files through Django, disable collectstatic by removing django.contrib.staticfiles from INSTALLED_APPS. The build skips the step automatically when it's absent.

See Deploying Django → Framework gotchas on Primcloud for the full Django checklist.

Common runtime errors#

App doesn't bind to $PORT#

Symptom: the deployment reaches Release Succeeded but the URL returns a connection error, and the runtime log has no "Listening" line from Gunicorn (or your WSGI/ASGI server).

Fix. Make sure the web command in your Procfile passes the port through:

Gunicorn:

Procfile
web: gunicorn myapp.wsgi --bind 0.0.0.0:$PORT

Gunicorn's default is 127.0.0.1:8000, which won't be reachable from outside the pod. Bind to 0.0.0.0 and the port in $PORT.

Uvicorn:

Procfile
web: uvicorn myapp.asgi:application --host 0.0.0.0 --port $PORT

ModuleNotFoundError at startup#

Symptom: the pod starts and immediately crashes with ModuleNotFoundError: No module named '<something>'.

Fix. The package isn't in the installed venv:

  • Confirm the package is listed in requirements.txt / pyproject.toml, and that the lockfile (poetry.lock / uv.lock) was regenerated after adding it.
  • If it's a first-party module in your repo, confirm the file is checked into git and the import path matches the directory structure.
  • If it worked locally but not on Primcloud, you may have a package installed globally on your dev machine that's not in the lockfile. Install into a fresh venv locally to reproduce.

Missing shared library at runtime#

Symptom: OSError: libmagic.so.1: cannot open shared object file: No such file or directory (or similar) when the process starts.

Fix. Declare the OS package in project.toml; see Customizing the build → Debian packages. For libmagic, add libmagic1; for libpq, add libpq-dev; and so on.

App exits immediately on start#

The runtime log shows the process starting and then exiting with a non-zero code with no other output.

Most common causes:

  • Import-time exception before logging is configured. Add a top-level try / except around your app's entrypoint that prints the exception to sys.stderr before re-raising, redeploy, and check runtime logs for the traceback.
  • Missing required env var. If your app reads a connection string or API key at import time and raises on None, set it in the Secrets panel and redeploy.
  • Gunicorn worker timeout. Long-running import-time work (loading a large model, warming a cache) can exceed Gunicorn's 30-second worker start timeout. Bump --timeout in the web command or move the heavy work behind a lazy loader.

Debugging tips#

  • Reproduce the install locally. Run the same command the build runs (see Package managers → Install behavior) against a fresh Python of the version in .python-version. Most install failures reproduce this way.
  • Watch the version-resolution log line. The build log's early output prints the resolved Python version and where the requirement came from (the default or .python-version). If the resolved version isn't what you expected, check .python-version is at the repo root and committed.
  • Force a cache reset. Change .python-version to a different patch and back, or bump a dependency, to invalidate the venv layer if you suspect a stale cache.
  • Turn on Python's fault handler. PYTHONFAULTHANDLER=1 (set in the Secrets panel) makes Python print a traceback on segfaults, which helps with crashes in native extensions.