Stripe checkout endpoint returns 404 on production, works locally
aporchfulofpumpkins
FREEOP

16 days ago

I have a Node.js/Express app with a Stripe checkout integration. The /create-checkout-session endpoint works perfectly when running locally (npm start on localhost:4242), but returns a 404 error when deployed to Railway.

Error Messages:

  • Frontend: Failed to load resource: the server responded with a status of 404
  • Frontend: SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
  • This indicates the server is returning an HTML error page instead of the expected JSON response

What I've tried:

  • Pushed code to GitHub multiple times
  • Redeployed on Railway
  • Added environment variables (STRIPE_SECRET_KEY, STRIPE_PUBLISHABLE_KEY)
  • Code works perfectly locally

GitHub Repo:https://github.com/cookn1198/a-porchful-of-pumpkins

The /create-checkout-session endpoint is defined in Server.js (lines 16-38) but seems to not be accessible on the deployed Railway app, even though the server appears to start successfully.

$10 Bounty

2 Replies

Status changed to Open Railway 16 days ago


jedmond1971
HOBBY

16 days ago

Hello. I happened to come across your issue and wanted to see if Claude could make a suggestion. This is the response and I hope its helpful:

--------------------------------------------

This is a classic Railway deployment issue with two likely culprits — and they're both easy to fix.

🔴 Problem 1: Hardcoded localhost URL in the frontend (Most Likely Cause)

When you call /create-checkout-session locally, your frontend probably fetches something like:

fetch('http://localhost:4242/create-checkout-session', ...)

In production on Railway, localhost:4242 doesn't exist — the server is at your Railway public URL. So the request goes nowhere, and Railway's own 404 HTML page is returned instead of your JSON. That's exactly why you see:

SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON

Fix: Use a relative URL so it always points to the same server serving the frontend:

// ❌ Broken in production
fetch('http://localhost:4242/create-checkout-session', ...)

// ✅ Works everywhere
fetch('/create-checkout-session', ...)

🔴 Problem 2: Railway isn't using the right port

Railway assigns a dynamic port via the PORT environment variable. If Server.js hardcodes port 4242, Railway's proxy can't reach the app.

Check your server startup code. It should look like this:

// ❌ Hardcoded — breaks on Railway
app.listen(4242, () => console.log('Running on 4242'));

// ✅ Correct — reads Railway's assigned port
const PORT = process.env.PORT || 4242;
app.listen(PORT, () => console.log(`Running on port ${PORT}`));

🟡 Problem 3: package.json start script mismatch

Railway looks at your package.json"start" script to know how to run the app. Make sure it matches your actual entry point:

"scripts": {
  "start": "node Server.js"
}

If it says server.js (lowercase) but the file is Server.js (capital S), it will fail on Linux (Railway runs Linux, which is case-sensitive — unlike Windows/Mac).

Checklist to resolve

  1. Change fetch('http://localhost:4242/...') fetch('/create-checkout-session') in your frontend JS
  2. Update server to use process.env.PORT as shown above
  3. Verify package.json"start" script matches the exact filename casing of Server.js
  4. Redeploy — the fix should be immediate

The HTML-instead-of-JSON error is the dead giveaway that the fetch URL is pointing to the wrong place. Fix #1 alone will likely resolve it entirely.


aporchfulofpumpkins
FREEOP

16 days ago

@jedmond1971

Appreciate the help. I have been using Claude heavily in the development process and those issues don't seem to be the problem.


Welcome!

Sign in to your Railway account to join the conversation.

Loading...