PDFPipe

Platform as a service / Heroku

WeasyPrint on Heroku: an Aptfile and a library path

Deployment succeeds and the app crashes on boot with "cannot load library 'libpango-1.0-0'".

What is actually wrong

pip installs the Python package during the build and the C libraries it binds to are not part of the slug. Unlike the browser cases there is no size problem here at all: the libraries are small. The problem is purely that nothing has put them in the slug or told the dynamic linker where to look.

What Heroku gives you to work with

a slug built by buildpacks from your repository, run on a dyno with an ephemeral filesystem.

  • Packaging: the compiled slug has a 500 MB limit. A browser binary plus its shared libraries is a large fraction of that before your application is counted.
  • Filesystem: writable but ephemeral, and reset on every dyno restart, which happens at least daily. Nothing written at runtime survives.
  • Processes: a child process can be spawned, and it competes for the dyno's memory allowance. Exceeding that allowance produces a memory quota error in the logs rather than a crash, and the dyno keeps running while swapping.

The fix, if you are keeping WeasyPrint

Use the apt buildpack with an Aptfile listing the libraries and at least one font package. The buildpack installs them into the slug and sets the library path, which is the step that is easy to miss when doing this by hand.

bash
# Aptfile, committed to the repository:
#   libpango-1.0-0
#   libpangoft2-1.0-0
#   libharfbuzz0b
#   libcairo2
#   libgdk-pixbuf-2.0-0
#   fonts-dejavu-core

heroku buildpacks:add --index 1 heroku-community/apt
heroku buildpacks:add heroku/python

What still hurts after that

The library versions are whatever the platform stack ships, so a stack upgrade can move Pango underneath a pinned WeasyPrint and the symptom is bad text shaping rather than a build failure. This is still the cheapest of the four options to run here by a wide margin: no browser, no 500 MB slug, no memory quota warnings, in exchange for no JavaScript in the document.

What WeasyPrint is genuinely good at

it implements the parts of the paged media specification that browser engines never did, including running headers and footers in page margin boxes, and it uses a fraction of the memory a browser does. That is worth keeping in view: the problem on this page is where it runs, not what it produces. WeasyPrint is a Python library that implements CSS Paged Media directly, without a browser, on top of the Pango and Cairo text and graphics stack. It needs Pango, Cairo, HarfBuzz, GDK-PixBuf and GLib as system shared libraries. These are not Python packages and no wheel contains them.

The other shape of the answer

Every fix above keeps the renderer inside your deployment, which means the constraint stays yours: the package size, the shared libraries, the fonts, the memory, the patching. The alternative is an HTTP call from Heroku to something that already has a browser in it, which turns all of the above into a request and a response. That is what this API is, and it is the reason these pages exist. Whether that trade is right depends on whether rendering is a thing you want to operate.

Frequently asked

Can WeasyPrint run on Heroku at all?

Use the apt buildpack with an Aptfile listing the libraries and at least one font package. The buildpack installs them into the slug and sets the library path, which is the step that is easy to miss when doing this by hand. Whether that is worth doing is a separate question from whether it is possible, and the section above on what still hurts is the honest answer to it.

Why does it work locally?

Because a development machine has root, a package manager, several gigabytes of memory, a full font set and no packaging limit. Every one of those is a thing Heroku constrains. A renderer that works locally and fails on deploy has not regressed: it has met the first environment that does not give it everything.

Related failures

The same platform with a different renderer, and the same renderer on other platforms.

If the render moves off this platform, none of the above is your problem to keep solving. 100 free documents a month, and a playground that needs no signup.