Skip to content

Commit d0cadf3

Browse files
thomasballingerConvex, Inc.
authored andcommitted
Retry CLI push on environment variable race condition (#42429)
npx convex dev --once now retries on environment variable race condition, just like `npx convex dev` does GitOrigin-RevId: 499f7c234835489a28503de1cc3c4eb595e75142
1 parent 17413b3 commit d0cadf3

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

npm-packages/convex/src/cli/lib/config.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,16 @@ export function diffConfig(
10891089
return { diffString: diff, stats };
10901090
}
10911091

1092+
/** Handle an error from
1093+
* legacy push path:
1094+
* - /api/push_config
1095+
* modern push paths:
1096+
* - /api/deploy2/start_push
1097+
* - /api/deploy2/finish_push
1098+
*
1099+
* finish_push errors are different from start_push errors and in theory could
1100+
* be handled differently, but starting over works for all of them.
1101+
*/
10921102
export async function handlePushConfigError(
10931103
ctx: Context,
10941104
error: unknown,
@@ -1176,6 +1186,19 @@ export async function handlePushConfigError(
11761186
});
11771187
}
11781188

1189+
if (data?.code === "RaceDetected") {
1190+
// Environment variables or schema changed during push. This is a transient
1191+
// error that should be retried immediately with exponential backoff.
1192+
const message =
1193+
data.message || "Schema or environment variables changed during push";
1194+
return await ctx.crash({
1195+
exitCode: 1,
1196+
errorType: "transient",
1197+
errForSentry: error,
1198+
printedMessage: chalk.yellow(message),
1199+
});
1200+
}
1201+
11791202
if (data?.code === "InternalServerError") {
11801203
if (deploymentName?.startsWith("local-")) {
11811204
printLocalDeploymentOnError();

npm-packages/convex/src/cli/lib/deploy2.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export async function finishPush(
238238
url: string;
239239
dryRun: boolean;
240240
verbose?: boolean;
241+
deploymentName: string | null;
241242
},
242243
): Promise<FinishPushDiff> {
243244
changeSpinner("Finalizing push...");
@@ -262,8 +263,17 @@ export async function finishPush(
262263
});
263264
return finishPushDiff.parse(await response.json());
264265
} catch (error: unknown) {
265-
logFailure("Error: Unable to finish push to " + options.url);
266-
return await logAndHandleFetchError(ctx, error);
266+
return await handlePushConfigError(
267+
ctx,
268+
error,
269+
"Error: Unable to finish push to " + options.url,
270+
options.deploymentName,
271+
{
272+
adminKey: options.adminKey,
273+
deploymentUrl: options.url,
274+
deploymentNotice: "",
275+
},
276+
);
267277
}
268278
}
269279

0 commit comments

Comments
 (0)