16th of April. Yesterday I updated my unstable Nix channel. And now FastAPI is broken. Interesting… This is a good occasion to learn how to fix it! Let’s dig into it.

Fixing bug #1

First we need to understand what is the bug. A quick search on google gives this interesting link to track the origin of the bug: https://nixos.wiki/wiki/Nixpkgs/Create_and_debug_packages.

Let’s do steps 8, 9 and 10 of “Packages from source code”:

First let’s run a nix-build:

nix-build -A python310Packages.fastapi

Python tests are broken. Can we get more details?

Let’s continue with nix-shell:

nix-shell -A python310Packages.fastapi

Then we run all the phases manually:

cd $(mktemp -d)
unpackPhase
cd *
patchPhase
flitBuildPhase
pipInstallPhase
pythonImportsCheckPhase
pytestCheckPhase

How did I find the relevant phases ? Some are in the documentation, other are found thanks to the nix-build command (you can do a nix-build -A python310Packages.fastapi 2>&1 | grep Phase) and patchPhase is just… guessed…

The output of pytestCheckPhase is nearly the same as pytest --asyncio-mode=strict, except that 5 tests are deselected. We found this error message:

ModuleNotFoundError: No module named ‘orjson’

Haha !

Indeed, orjson is specified in https://github.com/tiangolo/fastapi/blob/master/pyproject.toml#L61 but not in https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/development/python-modules/fastapi/default.nix#L84!

Let’s correct this, then rerun the process.

Fixing bug #2

Now we get a different error message:

/nix/store/cgsmzrg190c7a79xk7n2gpqcjsrl77vz-python3.10-starlette-0.18.0/lib/python3.10/site-packages/starlette/responses.py:50: in __init__ > […] TypeError: ‘<’ not supported between instances of ‘NoneType’ and ‘int’

This seems to be a versioning issue. Upstream FastAPI requires Starlette 0.17.1. And here we are using Starlette 0.18.0. The error seems to be known and there is an open PR (since end of January) to update Starlette.

Now that we know the bug. Let’s try to fix it by generating the patch:

git clone https://github.com/tiangolo/fastapi.git
cd fastapi
git remote add Kludex git@github.com:Kludex/fastapi.git
git fetch Kludex
git checkout -b bump/starlette-0.18.0 Kludex/bump/starlette-0.18.0
git rebase 0.75.1
git diff 0.75.1 > /tmp/starlette-0.18.0.patch

And tada ! We got the patch. (I later discover that a simple call to https://patch-diff.githubusercontent.com/raw/tiangolo/fastapi/pull/4483.patch does exactly the same thing)

Now let’s add the patch to FastApi derivation:

patches = [ ./starlette-0.18.0.patch ];

Another option would be:

patches = [
  # Bump starlette, https://github.com/tiangolo/fastapi/pull/4483
  (fetchpatch {
    name = "support-later-starlette.patch";
    # PR contains multiple commits
    url = "https://patch-diff.githubusercontent.com/raw/tiangolo/fastapi/pull/4483.patch";
    sha256 = "sha256-ZWaqAd/QYEYRL1hSQdXdFPgWgdmOill2GtmEn33vz2U=";
  })
];

And it works \o/

Comparing with other solution

At this point I left for a few days of holidays. I didn’t have time to create the PR before leaving. At my return, someone else submitted a similar bugfix

Or… nearly similar. In this bugfix the patch is applied, but the orjson module is not installed, and a few tests are removed. Could we reactivate the test if we add orjson ?

Let’s go back to nix-shell. As expected, the version of FastAPI on master branch now can build. If we reactivate the tests, it fails. With orjson, it still fails. Sad. It seems there are other bugs that render orjson useless for now. But it is still something that will need to be added to Nix derivation at some point.