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
```
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:
Open
railway.json
.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).
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.
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.
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.
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?
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
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.
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.