{"record":{"id":"6799ec32aeae5751","repo":"commaai/openpilot","slug":"failed-to-preserve-corrupt-cabana-settings-s-s","errorCode":null,"errorMessage":"failed to preserve corrupt Cabana settings %s: %s\n","messagePattern":"failed to preserve corrupt Cabana settings (.+?): (.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"openpilot/tools/cabana/settings.cc","lineNumber":146,"sourceCode":"\n  if (!success) {\n    const int saved_errno = errno;\n    unlink(temporary_path.c_str());\n    fprintf(stderr, \"failed to save Cabana settings to %s: %s\\n\", path.c_str(), strerror(saved_errno));\n  }\n  return success;\n}\n\nbool preserveCorruptSettings() {\n  const auto path = settingsFile();\n  auto backup = path;\n  backup += \".corrupt\";\n  for (int i = 1; std::filesystem::exists(backup); ++i) {\n    backup = path;\n    backup += \".corrupt.\" + std::to_string(i);\n  }\n  if (rename(path.c_str(), backup.c_str()) < 0) {\n    fprintf(stderr, \"failed to preserve corrupt Cabana settings %s: %s\\n\", path.c_str(), strerror(errno));\n    return false;\n  }\n  fprintf(stderr, \"preserved corrupt Cabana settings at %s\\n\", backup.c_str());\n  return true;\n}\n\n// TODO: Remove the legacy QSettings migration after users have had time to migrate to cabana.json.\nstruct LegacyValue {\n  std::vector<std::string> strings;\n  std::string bytes;\n  bool is_byte_array = false;\n};\n\nusing LegacySettings = std::map<std::string, LegacyValue>;\n\nint hexDigit(char c) {\n  if (c >= '0' && c <= '9') return c - '0';\n  if (c >= 'a' && c <= 'f') return c - 'a' + 10;","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/cabana/settings.cc#L128-L164","documentation":"Emitted by preserveCorruptSettings() in tools/cabana/settings.cc when rename(cabana.json, cabana.json.corrupt[N]) fails. This function runs after settings were found invalid (error 140); it tries to move the bad file aside with a numbered backup name so the next save starts clean. A failure here means the corrupt file stays in place and will be re-reported on every startup.","triggerScenarios":"preserveCorruptSettings() reaching rename() when: the config dir is not writable (rename needs write on the directory, not the file), cabana.json was removed by another process between the exists() scan and the rename, the filesystem is read-only, or a file cabana.json.corrupt exists as a directory (the loop only walks existing names, then rename collides). The std::filesystem::exists loop found the first free .corrupt/.corrupt.N suffix, then rename returned < 0.","commonSituations":"Same permission problems as errors 141-142 (wrong user, read-only mount) — corrupt-file handling fails for the same environmental reason the parse failed; two cabana instances racing; corrupt backups accumulating because the parse error is never fixed.","solutions":["Fix directory write permission on <configPath>: that is what rename() needs (`chmod u+w <configPath>` / correct owner).","Manually move the file aside: `mv <configPath>/cabana.json <configPath>/cabana.json.manual` and restart.","Delete old cabana.json.corrupt* backups once the real file is fixed, so the suffix scan stays cheap and collision-free.","Close other cabana instances before restarting to avoid races."],"exampleFix":"# before\n# stderr: failed to preserve corrupt Cabana settings /home/user/.comma/cabana.json: Permission denied\n\n# after\nmv /home/user/.comma/cabana.json /tmp/cabana.json.bad\ncabana   # fresh cabana.json is written with defaults","handlingStrategy":"validation","validationCode":"// Before startup, verify the corrupt-file rename path would work:\nbool dirAllowsRename(const std::filesystem::path &dir) {\n  auto probe = dir / \".rename-probe\";\n  std::ofstream t(probe); t.close();\n  if (!std::filesystem::exists(probe)) return false;\n  auto target = dir / \".rename-probe.moved\";\n  bool ok = std::filesystem::rename(probe, target);  // needs write perm on dir\n  std::filesystem::remove(target);\n  return !ok ? false : true;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fix parse errors in cabana.json promptly; every startup re-reports and re-attempts the preserve while it stays corrupt.","Periodically clear cabana.json.corrupt* backups.","Ensure directory (not just file) write permission — rename() operates on the directory."],"tags":["cabana","settings","rename","corrupt-file","permissions"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}