commaai/openpilot · warning

failed to read Cabana settings %s%s%s

Error message

failed to read Cabana settings %s%s%s

What it means

Emitted by loadSettings() in tools/cabana/settings.cc when the Cabana settings file (utils::configPath()/cabana.json) exists and was read, but json11::Json::parse returned a non-empty error string or the parsed document is not a JSON object. It is a stderr diagnostic, not a thrown exception; loadSettings returns {.exists=true, .valid=false} and the caller falls back to defaults (typically after preserving the corrupt file).

Source

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

  }
  ~FileLock() {
    if (fd >= 0) close(fd);
  }
  bool isLocked() const { return fd >= 0; }

private:
  int fd = -1;
};

LoadedSettings loadSettings() {
  std::ifstream input(settingsFile());
  if (!input) return {};

  const std::string contents{std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>()};
  std::string error;
  auto settings_json = json11::Json::parse(contents, error);
  if (!error.empty() || !settings_json.is_object()) {
    fprintf(stderr, "failed to read Cabana settings %s%s%s\n", settingsFile().c_str(), error.empty() ? "" : ": ", error.c_str());
    return {.exists = true, .valid = false};
  }
  return {.values = settings_json.object_items(), .exists = true};
}

bool ensureSettingsDirectory() {
  const auto path = settingsFile();
  std::error_code error;
  std::filesystem::create_directories(path.parent_path(), error);
  if (error) {
    fprintf(stderr, "failed to create Cabana settings directory %s: %s\n", path.parent_path().c_str(), error.message().c_str());
    return false;
  }
  return true;
}

bool writeAll(int fd, const std::string &data) {
  size_t written = 0;

View on GitHub (pinned to 516ec1e682)

Solutions

  1. Fix or delete <configPath>/cabana.json and let Cabana regenerate it (a corrupt file is auto-renamed to cabana.json.corrupt by preserveCorruptSettings in the normal flow).
  2. Check the printed parse error (the trailing ': <error>' part names the JSON position) and correct that spot in the file.
  3. If the file is truncated from a crash, restore from cabana.json.corrupt.N backups or remove the file to start from defaults.
  4. Verify HOME/XDG config dir is writable and on a healthy filesystem so future saves are not truncated.

Example fix

// before (truncated/corrupt file):
{"openpilot": {"mode": "dark"   // <- file cut off, json11 parse error

// after:
{"openpilot": {"mode": "dark"}}
// or simply: rm ~/.comma/cabana.json  (path = utils::configPath()/cabana.json)
Defensive patterns

Strategy: validation

Validate before calling

// Validate the settings file before loadSettings() is relied upon:
#include <fstream>
#include <json11.hpp>
bool settingsFileValid(const std::filesystem::path &p) {
  std::ifstream in(p);
  if (!in) return false;                      // missing -> defaults, not an error
  std::string contents{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};
  std::string err;
  auto j = json11::Json::parse(contents, err);
  return err.empty() && j.is_object();        // mirrors loadSettings()'s own check
}

Prevention

When it happens

Trigger: Calling loadSettings() when cabana.json contains malformed JSON (truncated write, stray characters, BOM, trailing commas json11 rejects), or when the top-level JSON value is an array/string/number instead of an object. The ifstream open succeeded (otherwise the early `return {}` fires), so the file exists but its contents fail `json11::Json::parse(contents, error)` or `settings_json.is_object()`.

Common situations: Cabana killed mid-write in an older build that wrote the file non-atomically; hand-editing cabana.json and introducing a syntax error; disk-full truncation; a leftover file from a version with a different schema shape (e.g. top-level array).

Related errors


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