Skip to content

Commit ab03ab4

Browse files
committed
fix(onboard): explain a gateway database with a modified migration
sqlx reports a gateway database written by a newer OpenShell with one of two texts. Gateway start explains "is missing in the resolved migrations" but passed "migration N was previously applied but has been modified" through verbatim, with no database path, cause, or remedy. Classify both texts as an incompatible gateway database, print the same named-database recovery, and name both texts in the troubleshooting page. Refs: #9293 Signed-off-by: Udaya Tejas <udayatejas2004@gmail.com>
1 parent c0b1862 commit ab03ab4

5 files changed

Lines changed: 43 additions & 9 deletions

File tree

docs/reference/troubleshooting.mdx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,16 +602,23 @@ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash
602602

603603
The next installer run must continue past the OpenShell installation step without reporting a version mismatch.
604604

605-
### Docker Driver Gateway Reports a Missing Migration
605+
### Docker Driver Gateway Reports an Incompatible Migration
606606

607-
Onboarding can stop when the Docker driver gateway log contains both parts of this error:
607+
Onboarding can stop when the Docker driver gateway log contains both parts of either error:
608608

609609
```text
610610
migration N was previously applied
611611
is missing in the resolved migrations
612612
```
613613

614-
NemoClaw identifies `<selected-state-dir>/openshell.db` as incompatible with the installed OpenShell migration set.
614+
```text
615+
migration N was previously applied
616+
has been modified
617+
```
618+
619+
The first error means the installed OpenShell migration set does not contain migration N.
620+
The second error means that migration set defines migration N with different contents.
621+
NemoClaw identifies `<selected-state-dir>/openshell.db` as incompatible with the installed OpenShell migration set for both errors.
615622
This failure can happen after an OpenShell downgrade.
616623
Installing a NemoClaw release that is older than the installed one performs that downgrade, because each release pins one OpenShell version and the installer reinstalls OpenShell at the pin.
617624
You reach that state in one of three ways:

src/lib/onboard/docker-driver-gateway-failure.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,16 @@ describe("reportDockerDriverGatewayStartFailure (#3111)", () => {
144144
}
145145
});
146146

147-
it("prints a shell-quoted state-directory move after confirming no gateway process remains (#8797)", () => {
147+
it("prints a shell-quoted state-directory move after confirming no gateway process remains (#8797, #9293)", () => {
148148
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "gw-fail-"));
149149
const stateDir = path.join(dir, "gateway state;echo it's ignored");
150150
const log = path.join(stateDir, "openshell-gateway.log");
151151
fs.mkdirSync(stateDir);
152152
fs.writeFileSync(
153153
log,
154154
[
155-
"Error: execution error: migration error: migration 6 was previously applied",
156-
" is missing in the resolved migrations",
155+
"Error: execution error: migration error: migration 4 was previously applied but",
156+
" has been modified",
157157
].join("\n"),
158158
);
159159
try {
@@ -166,6 +166,7 @@ describe("reportDockerDriverGatewayStartFailure (#3111)", () => {
166166
const joined = errSpy.mock.calls.map((c: string[]) => c.join(" ")).join("\n");
167167
expect(joined).toContain("cannot use the existing gateway database");
168168
expect(joined).toContain(`Database: ${path.join(stateDir, "openshell.db")}`);
169+
expect(joined).toContain("does not include, or defines with different contents");
169170
expect(joined).toContain("it'\\''s ignored'");
170171
expect(joined).toContain("it'\\''s ignored.incompatible'");
171172
expect(joined).toContain("contains credentials and all registrations");

src/lib/onboard/docker-driver-gateway-failure.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,9 @@ function printIncompatibleGatewayDatabaseRecovery(
6666
: onboardResumeRecoveryCommand();
6767
printError(" The installed OpenShell version cannot use the existing gateway database.");
6868
printError(` Database: ${path.join(stateDir, "openshell.db")}`);
69-
printError(" The database records a migration that this OpenShell version does not include.");
69+
printError(
70+
" The database records a migration that this OpenShell version does not include, or defines with different contents.",
71+
);
7072
printError(" This can happen after an OpenShell downgrade.");
7173
const stopCommand = resolveGatewayStopCommand();
7274
if (!stopCommand && isGatewayStateInUse?.() !== false) {

src/lib/onboard/gateway-start-failure.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ describe("classifyGatewayStartFailure", () => {
7373
});
7474
});
7575

76+
it("classifies a modified applied migration as an incompatible database (#9293)", () => {
77+
const output = [
78+
"Error: × execution error: migration error: migration 4 was previously applied but",
79+
" │ has been modified",
80+
].join("\n");
81+
82+
expect(classifyGatewayStartFailure(output)).toEqual({
83+
kind: "database_migration_incompatible",
84+
});
85+
});
86+
87+
it("does not classify an on-disk migration-file edit as incompatible database state (#9293)", () => {
88+
const output = "the file containing migration 6 has been modified on disk";
89+
90+
expect(classifyGatewayStartFailure(output)).toEqual({ kind: "unknown" });
91+
});
92+
7693
it("does not classify an unrelated SQLite migration failure as incompatible database state (#8797)", () => {
7794
const output = "database is locked while applying migration 6";
7895

src/lib/validation.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@ export interface GatewayStartFailure {
4242
* dockerd on Linux) is not responding. Retrying the openshell health
4343
* poll cannot recover from this — the user must start Docker first.
4444
* - `database_migration_incompatible`: the gateway database records a
45-
* migration that the installed OpenShell version does not include.
45+
* migration that the installed OpenShell version does not include, or
46+
* defines with different contents. Both sqlx signatures mean the database
47+
* was written by a newer OpenShell than the one now starting (#8797,
48+
* #9293).
4649
* - `unknown`: any other failure; callers should fall through to the
4750
* normal retry/health-wait behavior.
4851
*/
@@ -224,8 +227,12 @@ export function planSandboxCreateRecovery(
224227
*/
225228
export function classifyGatewayStartFailure(output = ""): GatewayStartFailure {
226229
const text = String(output || "");
230+
// Both sqlx migrate signatures for a database written by a newer OpenShell:
231+
// the newer build appended a migration this build does not resolve
232+
// ("is missing in the resolved migrations"), or it rewrote an applied
233+
// migration so the checksum no longer matches ("has been modified").
227234
if (
228-
/migration\s+\d+\s+was previously applied[\s\S]{0,512}\bis missing in the resolved migrations\b/i.test(
235+
/migration\s+\d+\s+was previously applied[\s\S]{0,512}\b(?:is missing in the resolved migrations|has been modified)\b/i.test(
229236
text,
230237
)
231238
) {

0 commit comments

Comments
 (0)