Fix Heroku "Failed to Compile Python App" for Django
Fix Heroku push rejected, failed to compile Python app for Django: set the Python version with .python-version, fix requirements and lock files, resolve packages that need system libraries, and clear a stale build cache.
Problem statement
A push to Heroku stops before your app ever runs:
remote: -----> Building on the Heroku-24 stack
remote: -----> Using buildpack: heroku/python
remote: -----> Python app detected
remote: ! Requested Python version 3.9.18 is not available for this stack (heroku-24).
remote: ! Push rejected, failed to compile Python app.
or the dependency step fails:
remote: error: subprocess-exited-with-error
remote: × Building wheel for some-package (pyproject.toml) did not run successfully.
remote: ! Push rejected, failed to compile Python app.
"Failed to compile Python app" is the buildpack's generic failure message. The cause is one of a few build steps: detecting the app, choosing the Python version, installing dependencies, or running collectstatic. The lines just above it say which.
- Detection fails: commit
requirements.txt,poetry.lock, oruv.lockat the repository root. - Version not available: put a supported version in
.python-version, such as3.13. - Package build fails: upgrade the package to a version with wheels for your Python, or pin a compatible release.
- Conflicting requirements: regenerate the lock file locally and commit it.
- Odd errors after changes: clear the build cache with
heroku builds:cache:purge.
Step-by-step solution
1. Make sure Heroku detects a Python app
The buildpack looks for requirements.txt, poetry.lock, uv.lock, or a Pipfile in the root of the pushed branch. If your Django project lives in a subdirectory, either move the dependency file to the root or use a monorepo buildpack. Also check you pushed the right branch: git push heroku main pushes your local main.
2. Set the Python version
Current Heroku Python buildpacks read .python-version:
echo "3.13" > .python-version
git add .python-version && git commit -m "Pin Python for Heroku"
A major version like 3.13 gets the latest patch release automatically, which is the recommended form. Older stacks drop old Python versions, so a pin such as 3.9.18 fails after a stack upgrade. The older runtime.txt file is deprecated; migrate to .python-version.
3. Fix packages that will not build
When a package has no prebuilt wheel for the Python version, pip compiles it from source. Many fail because build tools or headers are missing on the stack, or because the old release does not support the new Python. Upgrading usually fixes it:
# requirements.txt
psycopg[binary]==3.2.10 # instead of psycopg2 without -binary
Pillow==11.3.0 # current releases ship wheels for new Pythons
Check that every pinned package supports your Python version. Packages that need system libraries not on the stack may require the Apt buildpack, but that is rarely necessary for Django apps.
4. Commit a consistent lock file
For Poetry or uv projects, the lock file must match pyproject.toml:
uv lock # or: poetry lock
git add uv.lock pyproject.toml && git commit -m "Refresh lock file"
A lock file generated on another Python version can pin packages that do not install on the Heroku version. Generate it with the same Python you set in .python-version.
5. Clear the build cache
Heroku caches installed packages between builds. After changing Python versions or package managers, a stale cache can cause confusing errors:
heroku plugins:install heroku-builds
heroku builds:cache:purge -a myapp
git commit --allow-empty -m "Rebuild" && git push heroku main
Explanation
The Heroku Python buildpack is a script that runs on the build server: it detects the project type, downloads a prebuilt Python for the stack, installs dependencies with the matching tool, and runs collectstatic. Each stack (Heroku-22, Heroku-24) is a different Ubuntu base with its own set of supported Python versions. When any step exits with an error, the buildpack prints its own failure message and the push is rejected, so the useful information is always above it.
Edge cases / notes
- Private packages. Dependencies from private Git repositories need credentials, usually a token in the URL set through a config var.
- Multiple buildpacks. If Node.js runs first and fails, the error comes from the Node buildpack; read its output separately.
- App size. Slugs over the size limit fail after a successful install; remove large files and use
.slugignore.
Next steps
- If the failure is in collectstatic, see Fix Heroku collectstatic Failed.
- Choose a dependency tool with uv vs Poetry vs pip for Django.
- Review the full deployment in Deploy Django on Heroku.
FAQ
Is runtime.txt still supported?
It is deprecated in favor of .python-version. Migrate to the new file to avoid warnings and future failures.
Should I pin an exact patch version?
Usually not. Pinning the major version, such as 3.13, gets security patches automatically.
Why did a build that worked yesterday fail today?
A stack or buildpack update, a new release of an unpinned package, or a dropped Python version. Lock dependencies and keep the Python version current.
Can Heroku build with uv?
Yes. The Python buildpack detects uv.lock and installs with uv.