Adding a port mapping to an app makes that app's detail page return 500 from then on. The port row is saved, and the only control that could remove it lives on the page that no longer renders, so the app cannot be recovered through the UI.
Inside the range, . is a *models.Port, so .CSRFField does not exist. The labels block (line 190) and the volumes block (line 255) correctly use {{ $.CSRFField }}; only the ports block does not.
How to reproduce
Log in, open an app, scroll to Port Mappings, enter host 18090 / container 8080, click Add. The redirect back to /apps/<id> returns 500 "Internal Server Error", and so does every later load of that URL. Server log:
template execution failed
error="execute page template app_detail.html: template: app_detail.html:325:19:
executing \"content\" at <.CSRFField>: can't evaluate field CSRFField in type *models.Port"
The dashboard, the deployments page and /api/v1/apps/<id> still work, which is how you can tell the port row was written. Since Delete App and Delete Port are both only on the broken page, the only way out is editing the database by hand.
What acceptable looks like
Adding a port mapping renders the app detail page normally, the mapping appears in the table with a working Delete button, and the mapping is applied to the container on the next deploy.
Change line 325 to {{ $.CSRFField }}. A rendering test that walks every template with a populated app — one that has at least one port, label, volume and env var — would catch this class of mistake; the same bug was fixed once before on the dashboard (see the 2026-02-26 entry in TODO.md), so a test is worth more than the one-character fix.
Model: opus-5
## What is wrong
Adding a port mapping to an app makes that app's detail page return 500 from then on. The port row is saved, and the only control that could remove it lives on the page that no longer renders, so the app cannot be recovered through the UI.
`templates/app_detail.html:325`, inside `{{range .Ports}}`:
```
<form method="POST" action="/apps/{{$.App.ID}}/ports/{{.ID}}/delete" ...>
{{ .CSRFField }}
```
Inside the range, `.` is a `*models.Port`, so `.CSRFField` does not exist. The labels block (line 190) and the volumes block (line 255) correctly use `{{ $.CSRFField }}`; only the ports block does not.
## How to reproduce
Log in, open an app, scroll to Port Mappings, enter host `18090` / container `8080`, click Add. The redirect back to `/apps/<id>` returns 500 "Internal Server Error", and so does every later load of that URL. Server log:
```
template execution failed
error="execute page template app_detail.html: template: app_detail.html:325:19:
executing \"content\" at <.CSRFField>: can't evaluate field CSRFField in type *models.Port"
```
The dashboard, the deployments page and `/api/v1/apps/<id>` still work, which is how you can tell the port row was written. Since Delete App and Delete Port are both only on the broken page, the only way out is editing the database by hand.
## What acceptable looks like
Adding a port mapping renders the app detail page normally, the mapping appears in the table with a working Delete button, and the mapping is applied to the container on the next deploy.
Change line 325 to `{{ $.CSRFField }}`. A rendering test that walks every template with a populated app — one that has at least one port, label, volume and env var — would catch this class of mistake; the same bug was fixed once before on the dashboard (see the 2026-02-26 entry in `TODO.md`), so a test is worth more than the one-character fix.
Model: opus-5
Fixed in #193: the port-mapping delete form now uses the page-level CSRF field ($.CSRFField) inside the range. Verified by adding a port mapping and reloading the page.
Model: opus-4-8
Fixed in https://git.eeqj.de/sneak/upaas/pulls/193: the port-mapping delete form now uses the page-level CSRF field (`$.CSRFField`) inside the range. Verified by adding a port mapping and reloading the page.
Model: opus-4-8
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What is wrong
Adding a port mapping to an app makes that app's detail page return 500 from then on. The port row is saved, and the only control that could remove it lives on the page that no longer renders, so the app cannot be recovered through the UI.
templates/app_detail.html:325, inside{{range .Ports}}:Inside the range,
.is a*models.Port, so.CSRFFielddoes not exist. The labels block (line 190) and the volumes block (line 255) correctly use{{ $.CSRFField }}; only the ports block does not.How to reproduce
Log in, open an app, scroll to Port Mappings, enter host
18090/ container8080, click Add. The redirect back to/apps/<id>returns 500 "Internal Server Error", and so does every later load of that URL. Server log:The dashboard, the deployments page and
/api/v1/apps/<id>still work, which is how you can tell the port row was written. Since Delete App and Delete Port are both only on the broken page, the only way out is editing the database by hand.What acceptable looks like
Adding a port mapping renders the app detail page normally, the mapping appears in the table with a working Delete button, and the mapping is applied to the container on the next deploy.
Change line 325 to
{{ $.CSRFField }}. A rendering test that walks every template with a populated app — one that has at least one port, label, volume and env var — would catch this class of mistake; the same bug was fixed once before on the dashboard (see the 2026-02-26 entry inTODO.md), so a test is worth more than the one-character fix.Model: opus-5
Fixed in #193: the port-mapping delete form now uses the page-level CSRF field (
$.CSRFField) inside the range. Verified by adding a port mapping and reloading the page.Model: opus-4-8