docs: capture stale-GRAV_VERSION api-plugin-install failure (ce-compound)
Fresh prod install ran Grav rc.10 (stale .env.prod GRAV_VERSION), so GPM would not serve the api plugin (needs >=2.0.4); admin2 (auth via /api/v1) then 404'd login silently. Documents the dead ends (deploying api config, gpm index -f, same-channel assumption) and the fix (self-upgrade core + reinstall + bump .env.prod). Adds reciprocal 'same 2026-07-04 cutover' cross-links across the three sibling deploy gotchas. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Np4cMQLF77i664CAQXySzU
This commit is contained in:
@@ -119,4 +119,5 @@ Setting `close_connection: false` means Grav never enters the manual connection-
|
||||
|
||||
- **Grav per-environment override mechanism** — `deploy/env/prod/system.yaml` applied via `make remote-apply-env-prod`, described in `CLAUDE.md` §1 ("Production mode — per-environment override"). The pattern that lets a prod-only setting like `debugger.shutdown.close_connection: false` ship without mutating the committed dev `system.yaml`.
|
||||
- **`docs/working/git-sync-notes.md`** — documents the `user/env/<hostname>/config/` override tree (where this fix physically lives on the server) and the caveat that config saved via Admin on the server stays server-only.
|
||||
- **`docs/solutions/integration-issues/stale-grav-version-blocks-api-plugin-install.md`** — sibling from the same cutover: Admin2 login failed because a stale `GRAV_VERSION` installed an rc core and GPM wouldn't serve the `api` plugin. Different root cause, same deploy.
|
||||
- **`docs/solutions/test-failures/new-user-grants-api-not-admin-on-admin2.md`** — a sibling gotcha from the same 2026-07-04 Grav 2.0.4 production cutover (account permission provisioning); different root cause, same deploy.
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "Admin2 login fails silently because a stale GRAV_VERSION installs an rc core below the api plugin's version floor"
|
||||
date: 2026-07-04
|
||||
category: docs/solutions/integration-issues
|
||||
module: "grav / production deploy / plugin install"
|
||||
problem_type: integration_issue
|
||||
component: authentication
|
||||
severity: high
|
||||
symptoms:
|
||||
- "Admin2 login at /admin silently fails: button disables then re-enables, no visible error, nothing written to grav.log"
|
||||
- "admin2 SPA background login POST to /api/... returns 404"
|
||||
- "/api/v1/pages returns 404 on prod but 401 locally (api plugin route not registered)"
|
||||
- "user/plugins/api directory does not exist on prod (plugin never installed)"
|
||||
- "gpm install api reports 'These packages were not found on Grav: api' even after gpm index -f"
|
||||
root_cause: config_error
|
||||
resolution_type: environment_setup
|
||||
related_components:
|
||||
- "gpm"
|
||||
- "admin2 plugin"
|
||||
- "api plugin"
|
||||
- "scripts/server-install.sh"
|
||||
- "Makefile remote targets"
|
||||
- ".env.prod"
|
||||
tags:
|
||||
- grav
|
||||
- gpm
|
||||
- admin2
|
||||
- api-plugin
|
||||
- plugin-dependency
|
||||
- version-compatibility
|
||||
- production-deploy
|
||||
- env-config
|
||||
---
|
||||
|
||||
# Admin2 login fails silently because a stale GRAV_VERSION installs an rc core below the api plugin's version floor
|
||||
|
||||
## Problem
|
||||
|
||||
On a fresh Grav production install, Admin2 login fails silently because the `api` plugin — which Admin2 authenticates through — never installed. GPM refused to serve it: a stale `GRAV_VERSION` in `.env.prod` had installed Grav `2.0.0-rc.10`, and the `api` plugin requires Grav core `>=2.0.4`. GPM filters offered packages by the installed core version, so on an rc.10 core the `api` plugin was excluded from results entirely and reported as "not found." Admin2 was present (and depends on `api`), but its login POST hit an `/api/...` route that was never registered, so authentication silently 404'd before it ever reached Grav's auth layer.
|
||||
|
||||
## Symptoms
|
||||
|
||||
- Admin login at `/admin` silently fails: the login button disables briefly, re-enables, and shows no error. **Nothing appears in `logs/grav.log`** — a wrong password *would* log a failed-attempt warning, so its absence means auth was never reached.
|
||||
- The Admin2 SPA's background login request (to an `/api/...` endpoint) returns **HTTP 404** with `content-type: application/json`.
|
||||
- `GET /api/v1/pages` returns **404** on prod, but **401 Unauthorized** on the working local install — i.e. the api route isn't registered on prod at all.
|
||||
- `ls user/plugins/api` on the server: **No such file or directory** — the plugin was never installed, even though `admin2` (which depends on it) was.
|
||||
- `php bin/gpm install ... api -y` → `"These packages were not found on Grav: api"`, even after `php bin/gpm index -f`.
|
||||
|
||||
## What Didn't Work
|
||||
|
||||
- **Committing/deploying the api plugin config** (`enabled` / `route` / `session_enabled`, moved from the untracked `user/plugins/api/api.yaml` into the tracked `user/config/plugins/api.yaml`). This was a real, necessary fix for a *different* latent problem, but it did not fix login: you cannot configure a plugin that isn't installed. Still 404.
|
||||
- **Forcing a GPM index refresh** (`php bin/gpm index -f`). No effect. "Package not found" here is not a stale-index problem — GPM filters the packages it offers by the installed Grav **core** version, and rc.10 is below the api plugin's `>=2.0.4` requirement, so `api` is excluded from results entirely.
|
||||
- **Assuming "same channel = same availability."** Local (Grav 2.0.4, `stable` channel) found `api` via `gpm info api`; prod (also `stable`) reported it "not found." The channel was identical — the difference was the Grav **core** version, which silently filtered the plugin out.
|
||||
|
||||
## Solution
|
||||
|
||||
The real cause is that prod was running the wrong Grav core. `scripts/server-install.sh` downloads `grav-admin-v${GRAV_VERSION}.zip`, and `.env.prod` still carried the stale pre-upgrade `GRAV_VERSION=2.0.0-rc.10`.
|
||||
|
||||
1. Upgrade the Grav core in place to stable (rc.10 → 2.0.7):
|
||||
```bash
|
||||
make remote-upgrade-grav-prod # php bin/gpm self-upgrade -y && php bin/grav cache
|
||||
```
|
||||
2. Install the plugins now that a compatible core is present (the api plugin resolves):
|
||||
```bash
|
||||
make remote-install-plugins-prod # php bin/gpm index -f && php bin/gpm install <plugins.txt> -y
|
||||
# => "Preparing to install API [v1.0.8] ... Success!"
|
||||
```
|
||||
3. Clear cache, then verify the api route is live and login works:
|
||||
```bash
|
||||
make remote-clean-prod
|
||||
curl -s -o /dev/null -w '%{http_code}\n' https://site/api/v1/pages
|
||||
# 401 (was 404) => plugin installed + routed
|
||||
```
|
||||
4. **Prevent recurrence:** update `.env.prod` to `GRAV_VERSION=2.0.4` so a future *fresh* install doesn't reinstall rc.10 (self-upgrade fixed the running server, not the env file). Keep the api plugin's functional config in the tracked `user/config/plugins/api.yaml` so it deploys on a clean clone.
|
||||
|
||||
## Why This Works
|
||||
|
||||
GPM (Grav Package Manager) only offers a plugin version whose declared Grav requirement is satisfied by the **installed core**. The `api` plugin requires Grav `>=2.0.4`; on a `2.0.0-rc.10` core there is no compatible version, so GPM reports the package as "not found" rather than a version conflict. Admin2 declares `api` as a hard dependency and performs all authentication over the api plugin's `/api/v1` JWT endpoints, so with `api` absent the login POST hits a route that doesn't exist (404) and never reaches Grav's auth layer — hence the silent failure with no `grav.log` entry. Upgrading the core to a stable `>=2.0.4` build makes GPM offer `api` again; installing it registers `/api/v1`, and Admin2's login flow succeeds.
|
||||
|
||||
## Prevention
|
||||
|
||||
- **Keep `.env.<env>` `GRAV_VERSION` current.** It is the version a *fresh* `make remote-install-<env>` bakes in; a stale value silently installs an old core. After any core upgrade, bump the env file too — self-upgrade only moves the running server. Note this is a *third* version-authority surface alongside `user/config/system.yaml` `gpm.releases` (channel) and `plugins.txt` — they must stay in sync.
|
||||
- **When GPM says "package not found" for a package you know is on your channel, check the target's Grav core version first** (`php bin/grav --version` on the server, or `make remote-diag-<env>`). GPM filters by core compatibility; "not found" often means "no version compatible with your core," not "missing from the index." `gpm index -f` will not help.
|
||||
- **Don't trust a top-level install "Success" to mean dependencies installed.** A fresh install can leave a plugin's declared dependency unsatisfied (here `admin2` installed but its `api` dependency didn't). Verify with `ls user/plugins/<dependency>`.
|
||||
- **Know the Admin2 ⇄ api coupling.** Admin2 authenticates via the api plugin's `/api/v1` endpoints; a missing or unrouted api plugin makes admin login fail *silently* (login POST 404s, nothing logged). A quick `curl /api/v1/pages` expecting `401` (not `404`) is a good post-deploy smoke check.
|
||||
|
||||
## Related
|
||||
|
||||
This is one of three independent gotchas from the same **2026-07-04 Grav 2.0.4 production cutover**:
|
||||
|
||||
- `docs/solutions/integration-issues/grav-double-content-encoding-garbage-page.md` — sibling: garbage-rendered pages from a double `Content-Encoding` header on a non-FastCGI host. Different root cause (HTTP compression), same deploy.
|
||||
- `docs/solutions/test-failures/new-user-grants-api-not-admin-on-admin2.md` — sibling: an authenticated account is denied an admin-gated page because `login new-user` auto-detect granted `api.*` but not `admin.*`. Different root cause (permission provisioning), same admin2/api area.
|
||||
- `docs/working/plans/2026-07-04-grav-2.0.4-upgrade.md` — the upgrade plan whose Global Constraints spell out the GPM version floors (`grav >=2.0.4`, `api >=1.0.6`) that cause the "package not found" on an rc core.
|
||||
- **api plugin config** in the tracked `user/config/plugins/api.yaml` (`enabled` / `route` / `session_enabled`) — must ship on a clean clone; necessary but not sufficient (the plugin must be installed first). See CLAUDE.md §0 "Plugin management".
|
||||
@@ -78,5 +78,6 @@ This site runs **Admin2 only** (the classic `admin` plugin is disabled), so auto
|
||||
|
||||
## Related Issues
|
||||
- `docs/working/plans/2026-07-04-grav-2.0.4-upgrade.md` — the self-contained test-account infrastructure shipped alongside the Grav 2.0.4 upgrade.
|
||||
- Sibling gotchas from the same 2026-07-04 Grav 2.0.4 production cutover (all surface around admin2/api but with distinct root causes): `docs/solutions/integration-issues/stale-grav-version-blocks-api-plugin-install.md` (stale `GRAV_VERSION` → rc core → GPM won't serve the `api` plugin → login 404s) and `docs/solutions/integration-issues/grav-double-content-encoding-garbage-page.md` (double `Content-Encoding` header → garbage page).
|
||||
- `docs/solutions/architecture-patterns/dual-repo-submodule-workflow.md` — accounts live in the `user/` repo; the `testrunner` account is gitignored so it never reaches production.
|
||||
- GPX manager auth model (`access.admin.login: true` frontmatter + Login plugin) — see the project's GPX manager notes.
|
||||
|
||||
Reference in New Issue
Block a user