Support request: uploads consistently aborted partway through, cause not identified after extensive elimination
hellrazor777
HOBBYOP

17 days ago

Service: layermate-website | Volume ID: vol_qlmd2hu8mj44y8bf | Plan: Free, then upgraded to Hobby — identical failure on both

Symptom

Uploading a ~172.5MB file to an authenticated admin endpoint fails almost every time. Rebuilt to upload in 8MB chunks as separate sequential POST requests (~22 total) to work around it, but the interruption still happens on nearly every attempt — just mid-chunk now instead of mid-file.

Fails consistently after ~19-22 requests / ~80-90 seconds in, regardless of file or chunk size.

Every failure shows the same trace server-side:

Error: Request aborted

  at IncomingMessage.<anonymous> (/app/node_modules/multer/lib/make-middleware.js:124:28)

  at abortIncoming (node:_http_server:838:9)

  at socketOnClose (node:_http_server:832:3)

  at Socket.emit (node:events:531:35)

  at TCP.<anonymous> (node:net:347:12)

The underlying TCP socket for an in-flight request is closed from outside the Node process.

Sometimes immediately followed by the container itself stopping:

npm error signal SIGTERM

npm error command sh -c node server.js

Stopping Container

One run's npm debug log timestamp: 2026-08-04T08_53_30_338Z.

Client-side, it's a generic Failed to fetch — consistent with a reset connection, not an HTTP error response.

Ruled out, with evidence

Disk/volume space — Volume Usage showed ~200-300MB used of 500MB at failure time.

CDN/WAF in front — DNS/headers resolve straight to Railway's edge (server: railway-hikari, x-railway-edge), no Cloudflare etc.

App body-size limits — no limit applies to the multipart routes; multer's fileSize cap is above the 8MB chunk size.

Node/Railway timeouts — requestTimeout/headersTimeout raised to 14 min app-side; failures happen at ~80-90s, nowhere close.

RAM — identical failure on Free (512MB) and Hobby (48GB); not plausible an 8MB-chunk upload exhausts 48GB.

Healthcheck — Healthcheck Path is empty for this service.

Mid-upload redeploy — Deployments tab showed no new deployment at failure time.

Our own rate limiting — only applied to /api/login, /api/signup, /api/forgot-password, never these routes.

Memory leak — 15 consecutive full 150MB upload cycles (2.25GB total) run locally against the same code; RSS stayed flat 234-254MB, no growth.

Client network — same file uploaded to Google Drive on the same connection, no issues, ~2 minutes (longer than our failure window).

Simple connection-flood block — 30 rapid GETs from an unrelated network all returned 200 in ~0.35s each, no degradation (though this doesn't fully replicate authenticated POSTs with an 8MB payload, which I couldn't test without a live session).

What we're asking

This looks like something between Railway's edge and this container that isn't visible app-side. Could you check:

Any recorded restart/stop events for this service around the failure timestamps, and their stated cause?

Any edge/proxy-level connection limits or anti-abuse heuristics that could reset a burst of ~20 sequential authenticated POSTs over ~80-90 seconds?

This service's actual configured resource limits, in case a lower per-service cap is still in effect separate from the account plan ceiling?

Happy to provide exact timestamps, project/service ID, or anything else useful.

Solved$10 Bounty

Pinned Solution

h707
FREE

17 days ago

If you're switching to Cloudflare R2 presigned URLs,

  1. S3 Client Setup: Configure @aws-sdk/client-s3 using your Cloudflare Account ID and R2 credentials.
  2. Presigned URL Generator: Generate a 15-minute PutObjectCommand presigned URL via @aws-sdk/s3-request-presigner on your Node backend.
  3. Direct Client Upload: Fetch the presigned URL from the browser and PUT the file payload directly to R2.
  4. CORS Configuration: Add ["GET", "PUT", "HEAD"] to allowed methods in your Cloudflare R2 bucket CORS settings.

6 Replies

Railway
BOT

17 days ago

This thread has been opened as a bounty so the community can help solve it.

Status changed to Open Railway 17 days ago


h707
FREE

17 days ago

You have to generate presigned S3/R2 URLs on the Node server and upload chunks directly from the browser to object storage.

Try to also Pass the node flags --max-old-space-size=4096 and explicitly force garbage collection hints


hellrazor777
HOBBYOP

17 days ago

On the memory flags: I don't think that's it in this case — we stress-tested the exact upload code locally with 15 consecutive 150MB cycles (2.25GB total) and RSS stayed flat in a 234–254MB band with no growth trend, and the identical failure also occurred on our Hobby plan (48GB RAM), so a heap ceiling doesn't fit the evidence.


I’d recommend using object storage for large file handling, instead of the files going directly into the volume. You’ll be able to generate presigned URLs for direct or multipart uploads.


hellrazor777

On the memory flags: I don't think that's it in this case — we stress-tested the exact upload code locally with 15 consecutive 150MB cycles (2.25GB total) and RSS stayed flat in a 234–254MB band with no growth trend, and the identical failure also occurred on our Hobby plan (48GB RAM), so a heap ceiling doesn't fit the evidence.

h707
FREE

17 days ago

Try adding a 50–100ms artificial delay (await new Promise(r => setTimeout(r, 100))) between sequential POST chunk requests to allow Envoy's buffer and Node’s I/O queue to flush back to zero.


h707

Try adding a 50–100ms artificial delay (await new Promise(r => setTimeout(r, 100))) between sequential POST chunk requests to allow Envoy's buffer and Node’s I/O queue to flush back to zero.

hellrazor777
HOBBYOP

17 days ago

No Luck we will go down the R2 setup


hellrazor777

No Luck we will go down the R2 setup

h707
FREE

17 days ago

If you're switching to Cloudflare R2 presigned URLs,

  1. S3 Client Setup: Configure @aws-sdk/client-s3 using your Cloudflare Account ID and R2 credentials.
  2. Presigned URL Generator: Generate a 15-minute PutObjectCommand presigned URL via @aws-sdk/s3-request-presigner on your Node backend.
  3. Direct Client Upload: Fetch the presigned URL from the browser and PUT the file payload directly to R2.
  4. CORS Configuration: Add ["GET", "PUT", "HEAD"] to allowed methods in your Cloudflare R2 bucket CORS settings.

Status changed to Solved medim 17 days ago


Welcome!

Sign in to your Railway account to join the conversation.

Loading...