Skip to content

Commit b7b629a

Browse files
committed
fix(auth): guard backup assessment against Windows EPERM/EBUSY
Wrap getActionableNamedBackupRestores in try-catch so a filesystem error (e.g. antivirus holding a backup file on Windows) skips the recovery prompt instead of crashing the login flow. Switch Promise.all to Promise.allSettled in getActionableNamedBackupRestores so one unreadable backup file does not block assessment of the rest.
1 parent 36a0a37 commit b7b629a

2 files changed

Lines changed: 21 additions & 4 deletions

File tree

lib/codex-manager.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4373,9 +4373,17 @@ async function runAuthLogin(): Promise<number> {
43734373
isInteractiveLoginMenuAvailable();
43744374
if (canPromptForRecovery) {
43754375
recoveryPromptAttempted = true;
4376-
const recoveryState = await getActionableNamedBackupRestores({
4377-
currentStorage: refreshedStorage,
4378-
});
4376+
let recoveryState: Awaited<
4377+
ReturnType<typeof getActionableNamedBackupRestores>
4378+
>;
4379+
try {
4380+
recoveryState = await getActionableNamedBackupRestores({
4381+
currentStorage: refreshedStorage,
4382+
});
4383+
} catch {
4384+
// Filesystem error (e.g. Windows EPERM/EBUSY) – skip recovery prompt
4385+
recoveryState = { assessments: [], totalBackups: 0 };
4386+
}
43794387
if (recoveryState.assessments.length > 0) {
43804388
const displaySettings = await loadDashboardDisplaySettings();
43814389
applyUiThemeFromDashboardSettings(displaySettings);

lib/storage.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1334,9 +1334,18 @@ export async function getActionableNamedBackupRestores(
13341334
? await loadAccounts()
13351335
: options.currentStorage;
13361336
const assess = options.assess ?? assessNamedBackupRestore;
1337-
const assessments = await Promise.all(
1337+
const settled = await Promise.allSettled(
13381338
backups.map((backup) => assess(backup.name, { currentStorage })),
13391339
);
1340+
const assessments = settled
1341+
.filter(
1342+
(
1343+
r,
1344+
): r is PromiseFulfilledResult<
1345+
Awaited<ReturnType<typeof assessNamedBackupRestore>>
1346+
> => r.status === "fulfilled",
1347+
)
1348+
.map((r) => r.value);
13401349

13411350
const actionable = assessments.filter(
13421351
(assessment) =>

0 commit comments

Comments
 (0)