fix(ui): actionable 413/504/401 toasts + VPS nginx deploy template
Production QA reported "Submit failed 413" on /generation and plain "Upload failed" (no detail) on resource upload. Root cause is the outer reverse-proxy nginx on the VPS — still on default `client_max_body_size 1m` — rejecting requests before they reach Odoo. The inner docker-nginx and Odoo limits were already raised in earlier commits; only the VPS proxy was left unpatched. UI side - Add `describeApiError(err, fallback, context)` helper in lib/api-client.ts. Maps common HTTP codes to human-readable, actionable toast descriptions (413 → "ask ops to raise nginx client_max_body_size", 504 → "server took too long, retry", 502 → "Odoo is restarting", 401 → "sign in again", 4xx/5xx → server error body + status code). - Use it in GenerationPage submit, ResourceManager upload, TeacherLibrary upload, CustomExamCreate save/publish. Replaces four slightly-different ad-hoc mappings with one source of truth. Deploy side - Add deploy/nginx-vps.conf.example: full TLS reverse-proxy template with the body/timeout knobs that must match Odoo's limit_request (128 MB) and limit_time_real (900 s). - Add docs/DEPLOY_413_504_FIX.md: step-by-step remediation guide for the team lead covering the 3 layers that can block large bodies (outer nginx, Cloudflare, Odoo worker) and how to verify each. Made-with: Cursor
This commit is contained in:
105
docs/DEPLOY_413_504_FIX.md
Normal file
105
docs/DEPLOY_413_504_FIX.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Why "Submit failed 413" and "Upload failed" still happen in production
|
||||
|
||||
QA keeps reporting that the following two actions fail on the deployed VPS
|
||||
while working locally:
|
||||
|
||||
- **Resource Manager → Upload**: toast shows "Upload failed" (no details).
|
||||
- **Generation → Submit module as exam for approval**: toast shows
|
||||
"Submit failed — 413".
|
||||
|
||||
Both are the same root cause: the **outer nginx reverse proxy** on the VPS
|
||||
(the one terminating TLS in front of the docker stack) is still using its
|
||||
default `client_max_body_size 1m` and short proxy timeouts. We already
|
||||
raised the inner limits in:
|
||||
|
||||
- `odoo.conf` / `odoo-docker.conf` → `limit_request 134217728` (128 MB) +
|
||||
`limit_time_real 900s`
|
||||
- `frontend/Dockerfile` → `client_max_body_size 128m` +
|
||||
`proxy_read_timeout 900s` + `proxy_request_buffering off`
|
||||
|
||||
But the **outer** nginx wasn't changed, so it still rejects the request
|
||||
(413) or times the proxied connection (504) before traffic ever reaches
|
||||
Odoo. Because the refusal happens at the proxy, nothing shows up in the
|
||||
Odoo logs — only in `/var/log/nginx/*.error.log`.
|
||||
|
||||
## Fix on the VPS (one-time, 2 minutes)
|
||||
|
||||
1. SSH to the VPS and back up the existing config:
|
||||
|
||||
```bash
|
||||
sudo cp /etc/nginx/sites-available/encoach /etc/nginx/sites-available/encoach.bak
|
||||
```
|
||||
|
||||
2. Copy the template from the repo and edit the `server_name` + TLS
|
||||
cert paths to match the real hostnames:
|
||||
|
||||
```bash
|
||||
sudo cp deploy/nginx-vps.conf.example /etc/nginx/sites-available/encoach
|
||||
sudo ln -sf /etc/nginx/sites-available/encoach /etc/nginx/sites-enabled/encoach
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
The critical lines added are:
|
||||
|
||||
```nginx
|
||||
client_max_body_size 128m; # matches Odoo limit_request
|
||||
client_body_timeout 900s;
|
||||
proxy_read_timeout 900s; # matches Odoo limit_time_real
|
||||
proxy_send_timeout 900s;
|
||||
proxy_request_buffering off; # stream uploads, don't buffer 100% on disk
|
||||
```
|
||||
|
||||
3. Smoke-test:
|
||||
|
||||
```bash
|
||||
# Upload a ~30 MB PDF through /api/resources — should return 200, not 413.
|
||||
# Submit a module from /generation — should return 201, not 413.
|
||||
tail -f /var/log/nginx/encoach.error.log # watch for "client intended to send too large body"
|
||||
tail -f /var/log/odoo/odoo-server.log # watch for the actual request hitting Odoo
|
||||
```
|
||||
|
||||
## If the 413 persists after the nginx change
|
||||
|
||||
The body is getting rejected by something upstream. Check in order:
|
||||
|
||||
1. **Cloudflare / WAF** — Cloudflare's default free-plan body cap is 100 MB
|
||||
for authenticated endpoints and as low as 1 MB on some enterprise
|
||||
rules. In the dashboard → Rules → Transform / Firewall, look for
|
||||
`request.body.size` restrictions.
|
||||
2. **Odoo worker (`limit_request`)** — verify
|
||||
`grep limit_request /etc/odoo/odoo.conf` shows at least `134217728`.
|
||||
If the config file was baked into the docker image and never rebuilt,
|
||||
`docker compose build backend && docker compose up -d backend`.
|
||||
3. **`ModSecurity` / CRL** — some VPS providers ship ModSecurity enabled
|
||||
by default (`SecRequestBodyLimit`, default 13 MB).
|
||||
|
||||
## If the 504 persists
|
||||
|
||||
504 = the upstream didn't respond in time.
|
||||
|
||||
- Confirm `proxy_read_timeout 900s` is actually in the running config
|
||||
(`nginx -T | grep proxy_read_timeout`).
|
||||
- Confirm `limit_time_real` in `odoo.conf` is at least 900 (default is
|
||||
120; a single AI generation with 4 modules can exceed 3 minutes).
|
||||
- For first-time submissions, Odoo may need to warm up its AI clients.
|
||||
Retry once after a minute.
|
||||
|
||||
## What the UI now tells the user
|
||||
|
||||
The frontend toast has been upgraded (see `lib/api-client.ts::describeApiError`).
|
||||
Users will now see, for example:
|
||||
|
||||
- **413**: _"The module is too large for the server to accept (HTTP 413).
|
||||
Try a smaller file / fewer tasks, or ask an admin to raise the nginx
|
||||
client_max_body_size and Odoo limit_request."_
|
||||
- **504**: _"The server took too long to respond (HTTP 504). The module
|
||||
may still be processing — wait a minute and reload before retrying."_
|
||||
- **502**: _"The backend is unreachable (HTTP 502). Odoo may be
|
||||
restarting — try again in a moment."_
|
||||
- **401**: _"Your session expired — please sign in again."_
|
||||
|
||||
This applies to:
|
||||
- Resource upload (admin + teacher library)
|
||||
- Exam generation submit
|
||||
- Custom-exam publish / save draft
|
||||
Reference in New Issue
Block a user