fix: db volume ownership and explicit error handling for write failures #3
1 Participants
Notifications
Due Date
No due date set.
Depends on
Reference: josh/Catalyst#3
Reference in New Issue
Block a user
Delete Branch "fix/db-permissions-and-error-handling"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Root cause of the 500 on create/update/delete: the non-root app user in
the Docker container lacked write permission to the volume mount point.
Docker volume mounts are owned by root by default; the app user (added
in a previous commit) could read the database but not write to it.
Fixes:
Dockerfile — RUN mkdir -p /app/data before chown so the directory
exists in the image with correct ownership. Docker uses this as a
seed when initialising a new named volume, ensuring the app user
owns the mount point from the start.
NOTE: existing volumes from before the non-root user was introduced
will still be root-owned. Fix with:
docker run --rm -v catalyst-data:/data alpine chown -R 1000:1000 /data
server/routes.js — replace bare
throw ein POST/PUT catch blockswith console.error (route context + error) + explicit 500 response.
Add try-catch to DELETE handler which previously had none. Unexpected
DB errors now log the route they came from and return a clean JSON
body instead of relying on the generic Express error handler.
server/db.js — wrap the boot init() call in try-catch. Fatal startup
errors (e.g. data directory not writable) now print a clear message
pointing to the cause before exiting, instead of a raw stack trace.
TDD: tests written first (RED), then fixed (GREEN). Six new tests in
tests/api.test.js verify that unexpected DB errors on POST, PUT, and
DELETE return 500 with { error: 'internal server error' } and call
console.error with the route context string.
Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
Root cause of the 500 on create/update/delete: the non-root app user in the Docker container lacked write permission to the volume mount point. Docker volume mounts are owned by root by default; the app user (added in a previous commit) could read the database but not write to it. Fixes: 1. Dockerfile — RUN mkdir -p /app/data before chown so the directory exists in the image with correct ownership. Docker uses this as a seed when initialising a new named volume, ensuring the app user owns the mount point from the start. NOTE: existing volumes from before the non-root user was introduced will still be root-owned. Fix with: docker run --rm -v catalyst-data:/data alpine chown -R 1000:1000 /data 2. server/routes.js — replace bare `throw e` in POST/PUT catch blocks with console.error (route context + error) + explicit 500 response. Add try-catch to DELETE handler which previously had none. Unexpected DB errors now log the route they came from and return a clean JSON body instead of relying on the generic Express error handler. 3. server/db.js — wrap the boot init() call in try-catch. Fatal startup errors (e.g. data directory not writable) now print a clear message pointing to the cause before exiting, instead of a raw stack trace. TDD: tests written first (RED), then fixed (GREEN). Six new tests in tests/api.test.js verify that unexpected DB errors on POST, PUT, and DELETE return 500 with { error: 'internal server error' } and call console.error with the route context string. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>