PDFPipe

Serverless functions / Azure Functions

WeasyPrint on Azure Functions: GLib is not a pip package

The function app deploys and every invocation fails on import with "cannot load library 'libgobject-2.0-0'".

What is actually wrong

The Python worker installs your requirements. It cannot install apt packages, because on the Consumption plan there is no package manager and no root. WeasyPrint's dependencies are C libraries, and the environment simply does not contain them.

What Azure Functions gives you to work with

a function host that runs your code inside an environment it manages, with the amount of control depending entirely on which hosting plan you chose.

  • Packaging: on the Consumption plan you deploy code, not an image, so there is no way to install a system package. Anything needing shared libraries that are not already present has no path to being there.
  • Filesystem: a temporary directory is writable and is not shared between instances. The application directory is read-only in the packaged deployment mode that Consumption uses.
  • Processes: the sandbox restricts what a function can spawn, and the restriction is tighter on Windows than on Linux. A custom container on a plan that supports one is the route that removes the restriction.

The fix, if you are keeping WeasyPrint

A custom container on a plan that supports one, with the libraries installed in the image. There is no code-only path: the requirement is a system library and the platform's code-only deployment mode has no way to add one.

What still hurts after that

Same trade as the Puppeteer case, with a smaller image and a much smaller memory footprint. If a container is going to be built anyway, WeasyPrint is a cheaper thing to run than a browser, as long as the documents do not depend on JavaScript.

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 Azure Functions 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 Azure Functions at all?

A custom container on a plan that supports one, with the libraries installed in the image. There is no code-only path: the requirement is a system library and the platform's code-only deployment mode has no way to add one. 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 Azure Functions 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.