Setup & operations

Troubleshooting

Identify whether a problem belongs to editing, permissions, publication or the running services.

GroCMS 0.1.0 · Reviewed 15 September 2026

Download this guide

Start with the action and the exact outcome

Record what you were trying to do, the item involved, the time and the visible error. Distinguish an unsaved browser change from a saved draft, and a saved draft from a published revision. A missing public change can be expected when only the working version has changed. If the error includes a request identifier, preserve it for the operator to correlate with logs. Do not include passwords, cookies, API tokens or full private environment files in the report.

Keep the editor open while resolving unsaved work. Copy important local text before navigating or refreshing if the interface reports a failed save. A server-side conflict means another accepted version has become the current base. Compare against that revision and deliberately reconcile your changes; blind retries with the old expected revision should continue to fail. Saving the same local input over somebody else's work is not the intended conflict recovery path.

Sources: Structured CMS errors; Request errors and authenticated API boundary; Local save state and conflict recovery.

Resolve publishing and permission errors

ResultLikely meaningNext step
VALIDATIONA field, date, component or identifier is invalidUse the message to repair the saved content; publish requirements may be stricter than draft requirements
CONFLICTWorking revision or publication state changedReload the current server version and reconcile before issuing a new decision
DEPENDENCYA required target is missing, unpublished or incompatibleInspect references and publish or replace the required target through an authorized workflow
FORBIDDENCurrent account or API scope cannot perform the actionAsk an administrator to review the actual role and intended responsibility
UNKNOWN_COMPONENTA saved layout uses an unsupported blockPreserve the draft and ask a developer to restore compatibility or migrate it

An open tab does not preserve an old role after access changes. A designer may inspect editorial content without being permitted to edit it, while an editor does not automatically own design publication. Hiding or enabling a button is not the final authority: the server checks each command. For a route collision, choose the intended unique path or plan an authorized route change; publishing should not overwrite another record's route.

Sources: Draft and publication validation; Publication, preview and schedule rules; Current role capabilities.

Check the selected revision and media access

A preview link can fail because it expired, because a different account opened it or because it names a revision that is no longer valid for that request. Preview selections expire after thirty minutes. Sign in as the creator and generate a fresh preview from saved work. A preview is not an anonymous sharing link, and viewing one does not publish its selected drafts. Compare the preview's chosen revisions with the versions actually saved in the editor.

For a missing image, first check the selected media version and its usage. Uploads and replacements begin without public references. Publishing content that uses the new version is a separate step; older published revisions continue to use their older media identifier. If both authorized administration access and public delivery fail for a known retained file, the operator should inspect the configured media volume and readiness rather than replacing immutable bytes manually. A public 404 can also be the correct result after withdrawal or for private content.

Sources: Publication, preview and schedule rules; Immutable media and access eligibility; Published and preview content eligibility.

Separate a blocked intention from a stopped worker

Inspect the schedule's state, selected revision, due time, timezone and recorded reason. A later draft edit does not change the pinned revision. A newer manual publication, canceled intent, revoked publishing account or changed dependency can make the schedule stale or blocked. Resolve that editorial condition and create the intended new schedule. Do not change timestamps directly in production tables to bypass the state machine.

If valid due work remains pending, the operator should confirm that the separate worker is running, can reach the queue schema and is not deliberately paused for recovery. In development it needs its own npm run worker terminal. Production supplies a worker container. Temporary execution failures use retry metadata and preserve pending state while retries remain; deterministic publication failures are blocked visibly. Worker heartbeat health confirms connectivity, but only a real completed schedule proves the publication path ran.

Sources: Worker process and health; Retry and blocked-state handling; Publication, preview and schedule rules; Queue setup and retry configuration.

Inspect the correct environment without reinitializing it

Operators should first identify the environment. Development uses port 3100 and the separate gcms-dev infrastructure; ordinary production defaults to port 3000. Additional local installations use their own configured ports and cookie prefixes. A different URL may simply be a different database and account set. If Docker cannot connect, check its Linux engine before changing application configuration. If a port is occupied, identify the owning process instead of stopping unrelated projects.

powershell
docker compose --env-file .env.infrastructure.local -f compose.dev.yaml ps
docker compose --env-file .env.production.local --project-name gcms ps
docker compose --env-file .env.production.local --project-name gcms logs --tail 100 web worker db

A live web process can still report /api/ready as unavailable when database schema or media access is wrong. Missing tables after a release point to migration or target-database configuration; inspect the deployment result. A failed controlled migration intentionally leaves web and worker stopped. Existing environment files and initial database roles are not reset by rerunning initialization. In particular, changing a Docker password variable does not rotate an already initialized role. Preserve the database and media while repairing the actual cause.

Sources: Production runtime configuration; Local infrastructure configuration; Migration failure and deployment behavior; Schema and media readiness checks; Preserved existing local configuration; PostgreSQL official Docker image.

Use measured limits when investigating slow responses

Check error rate, database connection pressure, query plans, worker backlog and media access before assuming every slow page is a browser problem. The 11 September 2026 reproduction at 100,000 records reached 11.603 seconds p95 and three HTTP errors. Query improvements reduced the ten-minute result to 778 ms p95 with no errors, but this still misses the 750 ms target; a phrase-heavy variant reached 2.196 seconds. The ten-minute 10,000-record run reached 119 ms p95 with no errors. These synthetic, 20-reader measurements on one shared host do not establish a universal record limit, production hosting guarantee or response-time agreement. Test a larger customer's representative site and search mix on the intended host before making capacity commitments.

When escalating, include the source or image revision, environment name, affected route or resource identifier, sanitized error and time, and the smallest reproducible action. Operators can then connect the report to logs and verification evidence without requesting credentials. Developers should reproduce suspected integrity failures against an isolated test database. Preserve authored content and valid backups throughout diagnosis; restoring, reseeding or deleting history is not an ordinary troubleshooting shortcut.

Sources: Normal and stress workload evidence; Operational diagnosis and recovery policy; Current verification inventory.