401 Unauthorized when running railway up
elias-py
PROOP

9 months ago

I am trying to deploy my app from gitlab-ci but not getting through
RAILWAYAPITOKEN=xxxxxxxxxxxxxxx railway whoami
is working fine. Then i did

RAILWAYAPITOKEN=xxxx railway link -p xxxxx -e xxxx -s xxxxx
this worked as well but when i tried

RAILWAYAPITOKEN=xxxxxxxx railway up --verbose --detach
i got Failed to upload code with status code 401 Unauthorized

Solved$10 Bounty

Pinned Solution

mycodej
HOBBY

8 months ago

No problem elias-py,

Yes, as long as "PR Environments" are enabled and your GitHub repo is properly linked to your Railway project, Railway will automatically create a new environment, deploy the PR branch, and clean it up once the PR is closed or merged — no GitHub Actions pipeline required.

Unless you have custom logic or special setup needs, you shouldn’t need to manage preview deployments manually.

9 Replies

elias-py
PROOP

9 months ago

N/A


elias-py
PROOP

9 months ago

I would like to know if the railway up is working from the CLI for someone, without running the railway login, only with some token


mycodej
HOBBY

9 months ago

Yes — railway updoes work from the CLI without running railway login, as long as you're using the correct token type.

The key is to use a Project Token, not an Account or Team token.

Here's the difference:

  • RAILWAY_API_TOKEN (Account/Team token): works for railway whoami, railway link, etc.

  • RAILWAY_TOKEN (Project token): required for railway up, redeploy, and accessing logs.

If you're seeing a 401 error when running railway up, it's likely because you're using RAILWAY_API_TOKEN where RAILWAY_TOKEN is expected.

What to do:

  1. In the Railway web UI, go to your project → Settings → Tokens → Generate Project Token.

  2. Set that token as the RAILWAY_TOKEN environment variable in your CI.

  3. Run railway up — no need to run railway login at any point.

Example in GitLab CI:

deploy:
  stage: deploy
  script:
    - RAILWAY_API_TOKEN=$RAILWAY_API_TOKEN railway link -p $PROJECT_ID -e $ENVIRONMENT_ID
    - RAILWAY_TOKEN=$RAILWAY_TOKEN railway up --verbose --detach

With the Project Token in place, railway up runs completely non-interactively — no login needed.


elias-py
PROOP

9 months ago

Yea I think that's my main issue, the RAILWAY_TOKEN is per environment, let me explain a little bit more my issue.

I'm trying to implement PR previews, so this is part of my github actions code

name: Deploy to Railway

on:
  pull_request:
    types: [opened, closed]

env:
  RAILWAY_API_TOKEN: ${{ secrets.RAILWAY_API_TOKEN }}
  SERVICE_ID: ${{ secrets.RAILWAY_SERVICE_ID }} # service ID to inject database variable into
  DUPLICATE_FROM_ID: "preview" # railway environment to duplicate from
  LINK_PROJECT_ID: ${{ secrets.RAILWAY_PROJECT_ID }} # project ID
  SERVICE_NAME: ${{ secrets.RAILWAY_SERVICE_NAME }}

jobs:
    pr_opened:
      if: github.event.action == 'opened'
      runs-on: ubuntu-latest
      container: ghcr.io/railwayapp/cli:latest
      steps:
      - name: Checkout PR code
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
      
      - name: Set Environment Name
        id: env-name
        run: |
          # For PR opened events, use the head ref (source branch)
          BRANCH_NAME="${{ github.head_ref }}"
          
          # Make it safe for Railway (lowercase, replace special chars)
          SAFE_ENV_NAME=$(echo ${BRANCH_NAME} | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g')
          
          # Remove multiple consecutive hyphens and trim leading/trailing hyphens
          SAFE_ENV_NAME=$(echo ${SAFE_ENV_NAME} | sed 's/--*/-/g' | sed 's/^-//' | sed 's/-$//')
          
          # Truncate to 30 chars if needed (Railway environment name limit)
          SAFE_ENV_NAME=${SAFE_ENV_NAME:0:30}
          
          echo "env_name=${SAFE_ENV_NAME}" >> $GITHUB_OUTPUT
          echo "Environment name: ${SAFE_ENV_NAME}"
      
      - name: Link to project and create PR environment
        run: |
          # Link to base environment first
          railway link --project ${{ env.LINK_PROJECT_ID }} --environment ${{ env.DUPLICATE_FROM_ID }}
          # Create new environment
          railway environment new ${{ steps.env-name.outputs.env_name }} --copy ${{ env.DUPLICATE_FROM_ID }}

But seems like this is NOT deploying the updated branch code to the new environment, as the deploy is showing the same code as my "preview" environment from which is duplicated, so I was trying to do the following in the CLI:

1. Create a new environment (with the branch name)
2. Deploy the code to that environment (Here is where I'm getting the 401 as the new environment is created from the CLI, and I don't have any project token created from that specific environment)

When I update my PR branch I do have the updated code bc I have activated the "Branch connection". So my only issue is the first time I'm not getting the updated branch code.

So, what should I do to have the right code on my first PR creation?


mycodej
HOBBY

9 months ago

To get the correct code deployed on the first PR creation, the key issue is that you're duplicating an environment (e.g. preview) and then trying to deploy to the new one — but the deployment fails because you don't have a valid Project Token for the new environment. That’s why you’re getting the 401 Unauthorized error.

By default, when you duplicate an environment via CLI (railway environment new ... --copy preview), it copies the environment config, but it doesn’t trigger a fresh deploy — so the new environment just points to the last build from the source. That’s why the code looks the same as the original, even though you expect it to deploy the new PR code.

So what should you do?

Best solution: Use Railway’s built-in PR environments

If you haven’t already, enable "PR Environments" in the Railway dashboard. This automates exactly what you're trying to do:

  • Automatically creates a new environment for each PR

  • Deploys the head commit of the PR

  • Cleans up on PR close

No need to manage tokens or run railway up manually — it just works out of the box for GitHub.

Alternative: Use GitHub Actions with a helper

If you want to keep control inside GitHub Actions, consider using this GitHub Action:
ayungavis/railway-preview-deploy

It:

  • Creates the environment

  • Deploys the current PR code to it

  • Cleans it up on close

  • Only needs your RAILWAY_API_TOKEN

If you must use the raw CLI approach:

You’ll need to:

  1. Create the environment via railway environment new

  2. Use the Railway GraphQL API to programmatically generate a Project Token for that new environment

  3. Set RAILWAY_TOKEN to that token before running railway up

That’s a more advanced route and harder to maintain, but it’s the only way to get railway up to work securely per environment with the CLI.

TL;DR

To have the correct code on first PR creation:

  • Enable PR environments in Railway (recommended), or

  • Use the railway-preview-deploy GitHub Action, or

  • Generate a project token for the new environment dynamically if you're sticking with the CLI (complex)

Let me know if you want futher help on the issue.


elias-py
PROOP

8 months ago

Thanks for your response mycodej,

I already have "PR environments" enabled, should this tool auto deploy the PR and close it without having any github actions pipeline?


mycodej
HOBBY

8 months ago

No problem elias-py,

Yes, as long as "PR Environments" are enabled and your GitHub repo is properly linked to your Railway project, Railway will automatically create a new environment, deploy the PR branch, and clean it up once the PR is closed or merged — no GitHub Actions pipeline required.

Unless you have custom logic or special setup needs, you shouldn’t need to manage preview deployments manually.


mycodej
HOBBY

8 months ago

Hey elias-py,

just checking in — did that help or are you still running into issues?


elias-py
PROOP

8 months ago

Hey mycodej, yes that helps me a lot, one more thing that I have now is that I'm doing a PR from a forked repo to the main repo, this main repo is connected to railway through the master branch, so I'm doing a PR from my forked:master to the original:master, but not environment deploy is triggered, do you know why is this?


Status changed to Solved brody 8 months ago


Loading...