'Downgrading is unsupported' after a config restore: the update guard was right
After a configuration restore, an updater refused with:
that release predates the gateway runtime these session stores now use. Downgrading is unsupported.
The operator requested an update. The restored configuration selected an older code line than the databases required. Restoring the intended per-install channel corrected target selection; bypassing the guard would have put incompatible code over newer state.
A newer release number can select older capabilities #
The checkout followed a development branch. Its session databases already contained runtime-ledger history. The restored configuration backup lacked the install’s channel record, so release selection fell back to the stable channel.
The stable release had a higher patch version, but it came from a release branch without those runtime-ledger tables. Version ordering did not describe the relevant capability ordering.
The historical guard checked two things: whether the proposed target descended from the running commit, and whether a non-descendant target contained the runtime schema marker. It also read the session stores for ledger rows. Its refusal named the affected stores and stopped before moving the checkout.
The implementation explained the consequence: older code could not delete or prune sessions with that runtime history. This was a specific compatibility check, not proof that every forward commit or every future schema change would be safe.
Repair target selection before changing code #
The diagnosis followed the configuration lookup:
- Identify the actual install path and the channel record associated with it.
- Compare that record with the backup that was restored. Check defaults when the record is absent.
- Resolve the updater’s proposed target to a commit, rather than relying on its release label.
- Compare the target’s ancestry and required state capabilities with the running checkout.
- Reassert the intended channel through the updater’s supported configuration command, then run its check-only mode.
The corrected check selected the development branch and reported available forward commits—that verified channel selection. The update itself was deliberately not run, so the record does not establish a completed runtime upgrade.
For a Git-based installation, this read-only check is useful once TARGET is set to the exact resolved commit. Run it inside that installation’s checkout:
git merge-base --is-ancestor HEAD "${TARGET:?Set TARGET to the resolved update commit}"
Exit status 0 means the target descends from the current checkout. Status 1 means it does not; other failures require investigation. A non-descendant can be a valid release-branch target, so this command alone is not a compatibility verdict. Check the particular schema capability named by the refusal.
A config-only restore can create a mixed generation #
The database kept its newer state while the restored configuration lost an additive setting. In this implementation, channel records were keyed by install path identity. Restoring an older backup, or moving an install without recreating its record, could therefore change how later updates were selected.
Deployment automation should assert the intended channel after install or restore, then read it back through the supported interface. Do not hard-code a path-derived identifier from another machine. Following a development branch is appropriate only when that is the deliberate operating policy; it is not a universal fix for update errors.
For an intentional rollback, follow the application’s documented procedure for compatible code and pre-upgrade data together. Preserve the current state first, and account for work absent from the older backup. Editing a schema-version value or removing ledger rows merely to silence the guard would discard the evidence it uses to protect the store.
Add an update-target check to your restore drill before allowing the restored installation to update itself.