commaai/openpilot · warning

failed to preserve corrupt Cabana settings %s: %s

Error message

failed to preserve corrupt Cabana settings %s: %s

What it means

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.

Source

Thrown at openpilot/tools/cabana/settings.cc:146

  if (!success) {
    const int saved_errno = errno;
    unlink(temporary_path.c_str());
    fprintf(stderr, "failed to save Cabana settings to %s: %s\n", path.c_str(), strerror(saved_errno));
  }
  return success;
}

bool preserveCorruptSettings() {
  const auto path = settingsFile();
  auto backup = path;
  backup += ".corrupt";
  for (int i = 1; std::filesystem::exists(backup); ++i) {
    backup = path;
    backup += ".corrupt." + std::to_string(i);
  }
  if (rename(path.c_str(), backup.c_str()) < 0) {
    fprintf(stderr, "failed to preserve corrupt Cabana settings %s: %s\n", path.c_str(), strerror(errno));
    return false;
  }
  fprintf(stderr, "preserved corrupt Cabana settings at %s\n", backup.c_str());
  return true;
}

// TODO: Remove the legacy QSettings migration after users have had time to migrate to cabana.json.
struct LegacyValue {
  std::vector<std::string> strings;
  std::string bytes;
  bool is_byte_array = false;
};

using LegacySettings = std::map<std::string, LegacyValue>;

int hexDigit(char c) {
  if (c >= '0' && c <= '9') return c - '0';
  if (c >= 'a' && c <= 'f') return c - 'a' + 10;

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Fix directory write permission on <configPath>: that is what rename() needs (`chmod u+w <configPath>` / correct owner).
  2. Manually move the file aside: `mv <configPath>/cabana.json <configPath>/cabana.json.manual` and restart.
  3. Delete old cabana.json.corrupt* backups once the real file is fixed, so the suffix scan stays cheap and collision-free.
  4. Close other cabana instances before restarting to avoid races.

Example fix

# before
# stderr: failed to preserve corrupt Cabana settings /home/user/.comma/cabana.json: Permission denied

# after
mv /home/user/.comma/cabana.json /tmp/cabana.json.bad
cabana   # fresh cabana.json is written with defaults
Defensive patterns

Strategy: validation

Validate before calling

// Before startup, verify the corrupt-file rename path would work:
bool dirAllowsRename(const std::filesystem::path &dir) {
  auto probe = dir / ".rename-probe";
  std::ofstream t(probe); t.close();
  if (!std::filesystem::exists(probe)) return false;
  auto target = dir / ".rename-probe.moved";
  bool ok = std::filesystem::rename(probe, target);  // needs write perm on dir
  std::filesystem::remove(target);
  return !ok ? false : true;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of commaai/openpilot@516ec1e682 (2026-08-15). Data as JSON: /api/errors/6799ec32aeae5751. Report an issue: GitHub.