HKUDS/Vibe-Trading · error · ValueError

invalid portfolio settings: root must be an object

Error message

invalid portfolio settings: root must be an object

What it means

Raised by SettingsStore.load when the portfolio settings JSON file parses successfully but its top-level value is not a JSON object (e.g. it is an array, string, or number). The loader expects a dict because it feeds the payload straight into parse_settings. This is a file-corruption / wrong-format error, distinct from a JSON syntax error which is raised earlier with the parser's message.

Source

Thrown at agent/src/portfolio/config.py:248

        self.connection_store = connection_store or ConnectionStore(connection_path)

    def load(self) -> PortfolioSettings:
        """Read persisted settings, creating an empty file on first use.

        Returns:
            The validated settings currently on disk.

        Raises:
            ValueError: If the file is unreadable, is not a JSON object, or
                fails validation.
        """
        if self.path.exists():
            try:
                payload = json.loads(self.path.read_text(encoding="utf-8"))
            except (OSError, json.JSONDecodeError) as exc:
                raise ValueError(f"invalid portfolio settings: {exc}") from exc
            if not isinstance(payload, dict):
                raise ValueError("invalid portfolio settings: root must be an object")
            settings = parse_settings(payload, self.connection_store)
            if any("profile_id" in source for source in payload.get("sources", [])):
                self.save(settings)
            return settings

        settings = PortfolioSettings()
        self.save(settings)
        return settings

    def save(self, settings: PortfolioSettings | dict[str, Any]) -> PortfolioSettings:
        """Validate and atomically persist settings with owner-only permissions.

        Args:
            settings: Settings object or raw dict to validate and store.

        Returns:
            The validated settings that were written.

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Inspect the settings file at the store's path and confirm the top level is an object like {"sources": [...]}
  2. Fix or restore the file (from backup or by deleting it to fall back to defaults, since load constructs PortfolioSettings() when the file is absent)
  3. If a custom tool writes the file, change it to json.dump({...}, ...) with a dict root
  4. Re-run settings_store.load() to confirm it parses

Example fix

// before
[{"id": "ibkr", "enabled": true}]
// after
{"sources": [{"id": "ibkr", "enabled": true}]}
Defensive patterns

Strategy: validation

Validate before calling

import json
from pathlib import Path

def settings_file_is_valid(path: Path) -> bool:
    try:
        return isinstance(json.loads(path.read_text(encoding="utf-8")), dict)
    except (OSError, json.JSONDecodeError):
        return False

Type guard

def is_settings_payload(payload: object) -> bool:
    return isinstance(payload, dict)

Try / catch

try:
    settings = store.load()
except ValueError as exc:
    if "root must be an object" in str(exc):
        # restore backup or delete file to fall back to defaults
        path.unlink(missing_ok=True)
        settings = store.load()
    else:
        raise

Prevention

When it happens

Trigger: The settings file at self.path contains valid JSON whose root is not an object, e.g. '[]', '"text"', '123', or 'null'. Happens when a user or script overwrites the file with a list of sources or raw serialized fragment instead of an object with keys like 'sources'.

Common situations: Hand-editing settings.json and wrapping everything in brackets; writing a list of sources from a custom script; a truncated or partially-written file from a crashed save; migrating from an older format that stored an array.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/555b19ed20ae9d67. Report an issue: GitHub.