abi/screenshot-to-code · error · HTTPException

Design systems storage must contain a list

Error message

Design systems storage must contain a list

What it means

Raised by read_design_systems() (500) when design-systems.json parses as valid JSON but the top-level value is not a list (e.g. an object like {"items": []}). The storage contract is a JSON array of design-system records; anything else is treated as structural corruption and fails every design-systems endpoint.

Source

Thrown at backend/routes/design_systems.py:79

    except KeyError:
        return None


def read_design_systems() -> list[DesignSystem]:
    file_path = get_design_systems_file_path()
    if not file_path.exists():
        return []

    try:
        raw_items = cast(list[Any], json.loads(file_path.read_text(encoding="utf-8")))
    except json.JSONDecodeError as exc:
        raise HTTPException(
            status_code=500,
            detail="Design systems storage is not valid JSON",
        ) from exc

    if not isinstance(raw_items, list):
        raise HTTPException(
            status_code=500,
            detail="Design systems storage must contain a list",
        )

    design_systems: list[DesignSystem] = []
    for raw_item in raw_items:
        design_system = parse_design_system(raw_item)
        if design_system:
            design_systems.append(design_system)
    return design_systems


def write_design_systems(design_systems: list[DesignSystem]) -> None:
    file_path = get_design_systems_file_path()
    file_path.parent.mkdir(parents=True, exist_ok=True)
    tmp_path = file_path.with_suffix(".json.tmp")
    serialized = json.dumps(
        [design_system.model_dump() for design_system in design_systems],

View on GitHub (pinned to d026163f58)

Solutions

  1. Rewrite the file as a top-level JSON array of records: [{"id": ..., "name": ..., "content": ..., "createdAt": ..., "updatedAt": ...}, ...].
  2. If you need the data, extract the inner list from the wrapper object and save it as the top level.
  3. Reset with '[]' if the contents are disposable.
  4. Verify with python -c "import json;print(type(json.load(open(<path>))))" -> should print <class 'list'>.

Example fix

# before: {"designSystems": [{"id": "1", "name": "DS"}]}
GET /api/design-systems  # 500

# after: [{"id": "1", "name": "DS", "content": "", "createdAt": "...", "updatedAt": "..."}]
Defensive patterns

Strategy: validation

Validate before calling

import json

def design_store_is_list(path: str) -> bool:
    try:
        return isinstance(json.loads(open(path, encoding="utf-8").read()), list)
    except (OSError, json.JSONDecodeError):
        return False

Type guard

def is_design_store_shape(value: object) -> bool:
    return isinstance(value, list)

Try / catch

try:
    systems = requests.get(url + "/api/design-systems").raise_for_status().json()
except requests.HTTPError as e:
    if e.response is not None and "must contain a list" in e.response.text:
        raise RuntimeError("storage schema wrong: top level must be a JSON array") from e
    raise

Prevention

When it happens

Trigger: Any /api/design-systems call after the file was replaced with a dict, a bare string, or a number — typically from a hand edit or an external tool writing a different schema.

Common situations: Users wrap the array in an object for 'readability'; migration scripts export a different shape; the file was overwritten by another application.

Related errors


AI-assisted analysis of abi/screenshot-to-code@d026163f58 (2026-08-14). Data as JSON: /api/errors/7c4c77eebb2839ac. Report an issue: GitHub.