{"record":{"id":"271a6b60fde1992d","repo":"can1357/oh-my-pi","slug":"settings-config-was-invalid-before-locking-and-is","errorCode":null,"errorMessage":"Settings config was invalid before locking and is now missing: ${filePath}; another process may have moved it aside","messagePattern":"Settings config was invalid before locking and is now missing: (.+?); another process may have moved it aside","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/config/settings.ts","lineNumber":1451,"sourceCode":"\t\t\tconst loaded = await this.#loadYamlIfPresentForWriteLocked(filePath, writePath, true);\n\t\t\treturn loaded.settings;\n\t\t});\n\t}\n\n\t/**\n\t * Read a YAML settings file while its write lock is held. Invalid files are\n\t * moved aside before reporting failure, so a later write can never truncate\n\t * the only copy of the user's configuration.\n\t */\n\tasync #loadYamlIfPresentForWriteLocked(\n\t\tfilePath: string,\n\t\twritePath: string,\n\t\trejectMissing = false,\n\t): Promise<LockedYamlLoadResult> {\n\t\tlet result = await this.#loadYamlIfPresent(writePath);\n\t\tconst generation = yamlGenerationFromLoadResult(result);\n\t\tif (result.kind === \"missing\" && rejectMissing) {\n\t\t\tthrow new Error(\n\t\t\t\t`Settings config was invalid before locking and is now missing: ${filePath}; another process may have moved it aside`,\n\t\t\t);\n\t\t}\n\t\tif (result.kind === \"invalid\") {\n\t\t\tresult = await this.#quarantineInvalidYamlLocked(writePath, result);\n\t\t\tthis.#quarantinedYamlTargets.set(filePath, writePath);\n\t\t}\n\t\treturn {\n\t\t\tsettings: this.#unwrapYamlLoadResult(filePath, result),\n\t\t\tgeneration,\n\t\t};\n\t}\n\n\tasync #quarantineInvalidYamlLocked(\n\t\tfilePath: string,\n\t\tresult: Extract<YamlLoadResult, { kind: \"invalid\" }>,\n\t): Promise<Extract<YamlLoadResult, { kind: \"invalid\" }>> {\n\t\tconst backupPath = `${filePath}.broken-${Date.now()}-${process.pid}-${randomUUID()}`;","sourceCodeStart":1433,"sourceCodeEnd":1469,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/config/settings.ts#L1433-L1469","documentation":"Thrown while reloading settings under a file lock: the settings YAML was determined invalid in an earlier pass, but when the loader re-acquires the lock and re-reads the file it has vanished (kind === \"missing\") and rejectMissing was requested. The library refuses to silently proceed because the invalid file may have been moved aside by a concurrent process, and overwriting/ignoring could lose user data.","triggerScenarios":"Two processes concurrently loading/saving settings.yaml; process A quarantines (renames) the invalid file while process B, which had already classified it as invalid, reopens under lock and finds it gone with rejectMissing=true.","commonSituations":"Multiple omp instances (TUI + worker/SDK) sharing the same settings file; an editor or sync tool deleting the file mid-flight; race between quarantine renames.","solutions":["Re-run the command — the file state has settled and a fresh load will use defaults or the restored file","Check for leftover *.broken-* backup files next to settings.yaml and restore/re-merge them","Avoid running multiple processes that rewrite the same settings file simultaneously"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await settings.load(); } catch (e) {\n  if (String(e).includes('now missing')) {\n    await Bun.sleep(250);\n    await settings.load(); // state has settled after the concurrent quarantine\n  } else throw e;\n}","preventionTips":["Avoid running multiple omp processes that rewrite the same settings file at once","Look for *.broken-* backups next to settings.yaml when this occurs","Use a single settings writer process or serialize settings writes"],"tags":["concurrency","settings","file-system"],"backgroundTag":"config-file-race","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}