uvicorn not found using railpack

joshuafcole
PRO

2 months ago

When I build using nixpacks, my python backend setup works as expected, however bun doesn't work to compile my frontend. On a tip in my previous thread, I was recommended to use railpack instead, which indeed seems to have fixed the bun issue, but now when I attempt to build and launch my my python backend, I get a new issue -- I can't seem to find uvicorn despite having installed it. As an aside, I tried to use the lovely railpack CLI tool, but I can't seem to figure out how to get railway to read from it? Do I have to build the image locally to configure railpack via code?

Here's the error I get on deploy:

Starting Container

/bin/bash: line 1: uvicorn: command not found

The corresponding railway.json:

{
  "$schema": "https://railway.com/railway.schema.json",
  "build": {
    "builder": "RAILPACK",
    "buildCommand": "pip install -e ./model-server"
  },
  "deploy": {
    "runtime": "V2",
    "numReplicas": 1,
    "startCommand": "uvicorn model_server.main:app",
    "sleepApplication": false,
    "multiRegionConfig": {
      "us-west2": {
        "numReplicas": 1
      }
    },
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}

And snippets of log from my build step showing uvicorn being installed:

```

You reached the start of the range → May 24, 2025 5:15 PM

[Region: us-west1]

╭─────────────────╮

│ Railpack 0.0.65 │

╰─────────────────╯

↳ Detected Python

Packages

──────────

python │ 3.11.12 │ railpack default (3.11)

Steps

──────────

▸ build

$ pip install -e ./model-server

Deploy

──────────

$ uvicorn model_server.main:app

Successfully prepared Railpack plan for build

context: g8n4-Z0aM

[internal] load build definition from railpack-plan.json

0s

resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.0.65

0s

docker-image://ghcr.io/railwayapp/railpack-frontend:v0.0.65@sha256:00f027b9b7d766b9fb05bd48e1480c7efc30bec0fb44641ae22900f4a208e83a

Cached

load build definition from railpack-plan.json

0s

[railpack] secrets hash

0s

docker-image://ghcr.io/railwayapp/railpack-builder:latest

Cached

loading .

0s

docker-image://ghcr.io/railwayapp/railpack-runtime:latest

0s

install apt packages: python3-dev

5s

mkdir /etc/mise

0s

create mise config

0s

install mise packages: python

2s

copy .

0s

pip install -e ./model-server

24s

Obtaining file:///app/model-server

...

Installing collected packages: wcwidth, sortedcontainers, pytz, asn1crypto, websockets, uvloop, urllib3, tzdata, typing-extensions, tomlkit, sniffio, six, shellingham, pyyaml, python-dotenv, pyjwt, pygments, pycparser, prompt-toolkit, platformdirs, pfzy, packaging, numpy, mdurl, jmespath, jiter, idna, httptools, h11, filelock, distro, click, charset_normalizer, certifi, annotated-types, uvicorn, requests, python-dateutil, pydantic-core, markdown-it-py, inquirerpy, httpcore, cffi, anyio, watchfiles, starlette, rich, pydantic, pandas, httpx, cryptography, botocore, typer, s3transfer, redwood, pyOpenSSL, pydantic-to-typescript, pydantic-settings, fastapi, anthropic, elocute, confocal, cli, boto3, snowflake-connector-python, source-snowflake, model-maker, model-server

Successfully installed annotated-types-0.7.0 anthropic-0.52.0 anyio-4.9.0 asn1crypto-1.5.1 boto3-1.38.23 botocore-1.38.23 certifi-2025.4.26 cffi-1.17.1 charset_normalizer-3.4.2 cli-0.1.0 click-8.1.8 confocal-0.1.2 cryptography-45.0.2 distro-1.9.0 elocute-0.1.0 fastapi-0.115.12 filelock-3.18.0 h11-0.16.0 httpcore-1.0.9 httptools-0.6.4 httpx-0.28.1 idna-3.10 inquirerpy-0.3.4 jiter-0.10.0 jmespath-1.0.1 markdown-it-py-3.0.0 mdurl-0.1.2 model-maker-0.1.0 model-server-0.1.0 numpy-2.2.6 packaging-25.0 pandas-2.2.3 pfzy-0.3.4 platformdirs-4.3.8 prompt-toolkit-3.0.51 pyOpenSSL-25.1.0 pycparser-2.22 pydantic-2.8.2 pydantic-core-2.20.1 pydantic-settings-2.8.1 pydantic-to-typescript-2.0.0 pygments-2.19.1 pyjwt-2.10.1 python-dateutil-2.9.0.post0 python-dotenv-1.1.0 pytz-2025.2 pyyaml-6.0.2 redwood-0.1.0 requests-2.32.3 rich-14.0.0 s3transfer-0.13.0 shellingham-1.5.4 six-1.17.0 sniffio-1.3.1 snowflake-connector-python-3.15.0 sortedcontainers-2.4.0 source-snowflake-0.1.0 starlette-0.46.2 tomlkit-0.13.2 typer-0.15.4 typing-extensions-4.13.2 tzdata-2025.2 urllib3-2.4.0 uvicorn-0.34.2 uvloop-0.21.0 watchfiles-1.0.5 wcwidth-0.2.13 websockets-15.0.1

WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour ...

[notice] A new release of pip is available: 24.3.1 -> 25.1.1 [notice] To update, run: pip install --upgrade pip

copy /mise/shims, /mise/installs, /usr/local/bin/mise, /etc/mise/config.toml, /root/.local/state/mise

0s

copy /app, /app

0s

[auth] sharing credentials for production-us-west2.railway-registry.com

0s

Build time: 50.76 seconds
```

$20 Bounty

10 Replies

2 months ago

Railpack installs all your Python packages into its own virtual-env at /app/venv. When the container boots it doesn’t add that venv’s “bin” folder to the default PATH, so a bare uvicorn call can’t be found even though the package is there.

Fix is simple actually:

  1. Open railway.json.

  2. Swap the startCommand for one of these lines:

    • /app/venv/bin/uvicorn model_server.main:app

    • or python -m uvicorn model_server.main:app (this also works because it asks Python to run the module directly).

  3. Commit and push and it'll rebuild the image and, this time, the backend starts because it’s pointing at the exact location of the Uvicorn binary.

You don’t need to build anything locally. Just that one path tweak, redeploy, and get some rest lol.


maycrash
HOBBY

2 months ago

Faced something similar before with Nixpacks + pip. Uvicorn was installed, but wasn’t available when the app started because it wasn’t in the system path.

What fixed it for me:

1. During the install phase, I made sure to install uvicorn explicitly using pip.

2. In the start command, I used:

uvicorn your_module:app --host 0.0.0.0 --port ${PORT:-8000}

Or, to avoid depending on the system path, this also works:

python -m uvicorn your_module:app --host 0.0.0.0 --port ${PORT:-8000}

That last one is more reliable if you’re running in a virtualenv or if pip doesn’t expose uvicorn globally.

Didn’t need to touch Docker or rebuild anything. Just added that and it worked.


2 months ago

Do you have an example repo that can be used to test? Everything installed with pip should be available on the global path.

The default install command for Python will add /app/.venv to the global path which will make all pip installed packages available.

    {
      "name": "install",
      "inputs": [
        {
          "step": "packages:mise"
        }
      ],
      "commands": [
        {
          "cmd": "python -m venv /app/.venv"
        },
        {
          "path": "/app/.venv/bin"
        },
        {
          "src": "requirements.txt",
          "dest": "requirements.txt"
        },
        {
          "cmd": "pip install -r requirements.txt"
        }
      ],

2 months ago

I've looked at your setup, an I think I have a solution that might work (although I'm not able to test on any real code). The key here is specifying the "provider" in the railpack.json file. You could then also specify other commands (like bun install) in the install step too.

I'm trying to understand your usecase a bit better though. Why are you trying to install everything custom instead of having Railpack detect the config automatically?

{
  "$schema": "https://schema.railpack.com",
  "packages": {
    "bun": "latest",
    "node": "latest"
  },
  "provider": "python",
  "steps": {
    "install": {
      "commands": [
        "...",
        "python -m venv /app/.venv",
        { "path": "/app/.venv/bin" },
        { "src": ".", "dest": "." },

        // Specific to your app
        "pip install -e ./server/model-server"
      ],
      "caches": ["pip"],
      "deployOutputs": []
    }
  },
  "caches": {
    "pip": {
      "directory": "/opt/pip-cache",
      "type": "shared"
    }
  },
  "deploy": {
    "inputs": [
      {
        "step": "packages:mise",
        "include": [
          "/mise/shims",
          "/mise/installs",
          "/usr/local/bin/mise",
          "/etc/mise/config.toml",
          "/root/.local/state/mise"
        ]
      },
      {
        "step": "build",
        "include": ["."]
      }
    ]
  }
}

testuser123

Railpack installs all your Python packages into its own virtual-env at /app/venv. When the container boots it doesn’t add that venv’s “bin” folder to the default PATH, so a bare uvicorn call can’t be found even though the package is there.Fix is simple actually:Open railway.json.Swap the startCommand for one of these lines:/app/venv/bin/uvicorn model_server.main:appor python -m uvicorn model_server.main:app (this also works because it asks Python to run the module directly).Commit and push and it'll rebuild the image and, this time, the backend starts because it’s pointing at the exact location of the Uvicorn binary.You don’t need to build anything locally. Just that one path tweak, redeploy, and get some rest lol.

joshuafcole
PRO

2 months ago

python -m uvicorn model_server.main:app

This was the second thing I tried actually! I'd have to wade through a several dozen test commits to find the exact incantation so we could try to find the discrepancy, but unfortunately neither uvicorn nor the other packages I installed were showing up in the found modules.


joshuafcole
PRO

2 months ago

Unfortunately the auto-detected configuration wasn't working at all for me. This is probably due to some misunderstanding on my part, but documentation was sparse. I managed to get things working (albeit briefly) with a slightly different configuration that manually created the venv, copied it over, and ran python from the venv -- but for reasons I still don't understand that stopped working remotely when building on railway (see the other thread I created, fails with code 137: https://station.railway.com/questions/local-railpack-build-succeeds-but-remote-1801c2f0). I eventually resorted to building an image with railpack locally, uploading it to ghci, and then using the docker image to deploy onto railway -- which seems to work fine but I was hoping to avoid.

This is the final railpack config which works perfectly locally:

I can live with this in the short term, but I'm still very interested in figuring out the root cause and letting railway handle the whole process automatically.

I'm not sure what the bug tracking etiquette is here -- should I close this issue and attempt to resolve in the other thread? Or would it be better to close that thread and consolidate here?


joshuafcole
PRO

2 months ago

Apologies, I'm having a heck of a time actually getting replies posted due to the frequent 403 errors. Every time I attempt to edit my comment to include the config it seems to fail, so here's a gist link: https://gist.github.com/joshuafcole/d95f2d50a749ef38278c2697e441b96f


joshuafcole
PRO

2 months ago

Following up, I attempted to set the provider (and added back in caching because it evidently wasn't the cause of the problem), and get the same code 137 abort, now during the apt install stage that got added.

Config: https://gist.github.com/joshuafcole/d4e32b928eecf11c45592efeee7bef7a

Logs: https://gist.github.com/joshuafcole/a3a9b7d321b8f5e5890db59d1f85eda5

It still works when built locally and I run the image.


2 months ago

This is useful to debug, thanks. One thing I immediately notice is that you are not updating the path after creating the venv, which is why you need to manually specify the path to uvicorn in the start command. That is not a big deal though.

More importantly, the error when building on Railway vs local.

This error, "/client/apps/modeler/dist": not found indicates that Railpack is trying to construct an image but failing to copy over that folder. Why it is trying to do that, I am not sure. It is likely building okay locally because that directory exists locally but does not exist when Railway is building (because of gitignore).

I'm not sure what the bug tracking etiquette is here

We can use either thread. I think the original problem of uvicorn not being found is solved? But it is useful to have all the context in a single place.

Do you have a link to the deployment on Railway that is failing. I'd like to see the full build plan there. It does seem like Railpack is incorrectly trying to copy files into the build context.

Additionally (and completely optional), you could create an issue in the Railpack repo, https://github.com/railwayapp/railpack/issues, with a link to a minimal GitHub repo where this problem occurs.


jr

This is useful to debug, thanks. One thing I immediately notice is that you are not updating the path after creating the venv, which is why you need to manually specify the path to uvicorn in the start command. That is not a big deal though.More importantly, the error when building on Railway vs local.This error, "/client/apps/modeler/dist": not found indicates that Railpack is trying to construct an image but failing to copy over that folder. Why it is trying to do that, I am not sure. It is likely building okay locally because that directory exists locally but does not exist when Railway is building (because of gitignore).I'm not sure what the bug tracking etiquette is hereWe can use either thread. I think the original problem of uvicorn not being found is solved? But it is useful to have all the context in a single place.Do you have a link to the deployment on Railway that is failing. I'd like to see the full build plan there. It does seem like Railpack is incorrectly trying to copy files into the build context.Additionally (and completely optional), you could create an issue in the Railpack repo, https://github.com/railwayapp/railpack/issues, with a link to a minimal GitHub repo where this problem occurs.

joshuafcole
PRO

2 months ago

Hey JR, really appreciate the help and apologies for the slow response time. We have a demo coming up shortly that we've been heads down on. Thanks to your earlier messages and the improved understanding of railpack they gave me, I was able to eventually land on a successful config, see attached. It could likely still be improved further, but it'll tide us over for the demo. After the demo ends, I'd like to come back with an MRE and see if we can work together to figure out what went wrong in the zeroconf flow -- if you prefer I can file a separate issue against railpack for that.

One other minor request for other folks adopting railway is to provide a clearer guide on the interplay between railpack and railway (esp. when some manual configuration is needed). In retrospect it's a lot clearer now what was going on, but not having prior experience with buildkit or an understanding of the difference between the emitted plan syntax and the railpack config itself led to a few frustrating hours of trying random permutations to railway to respect my attempts to configure railway. The two biggest doc wins there that would save past-me some time would be:

  • clarify the difference between who uses railpack.json, railpack-plan.json, and railway.json and for what

  • clarify the difference between the railpack configuration schema and the emitted railpack-plan schema -- I was using buildkit directly and hand-editing the plan (based on what it initially emitted for me) without realizing I was skipping a step.

Another deeper cut that would be excellent would be a sample repo that uses railpack and railway with manual configuration. If I'd started from a template like that I think I would have just stumbled into the happy path.

One outstanding question is why exactly we were hitting that code 137. I was originally writing off the failue to copy dist based on the fact that I was getting the error code 137 much earlier in the process, while trying to run the bun install. Building the frontend was sequenced after that, so of course it wouldn't be there if the frontend install had failed. It's not clear to me why railpack would have continued running after the install failure though, which has me wondering if perhaps I'm missing something about how railpack chooses to sequence tasks.


uvicorn not found using railpack - Railway Help Station