Hmbown/CodeWhale · error · ConversionError

Cannot parse portable data; use JSON for OpenCode or plain…

Error message

Cannot parse portable data; use JSON for OpenCode or plain YAML/JSON for DSH.

What it means

The converter's data() loader parses YAML or JSON input and deliberately swallows the parser's original error, raising this fixed ConversionError instead, because parser error text can leak source lines and credentials. It means the input file is neither valid JSON nor the plain YAML subset the converter accepts.

Solutions

  1. Validate the file with a JSON or plain YAML parser locally to find the syntax problem
  2. Convert exotic YAML (anchors, tags, multi-doc) to plain YAML or JSON before converting
  3. Check for binary corruption or wrong encoding in the file
  4. Reduce nesting to under 32 levels

Example fix

# before
base: &b
  a: 1
nested: *b   # anchors rejected
// after
nested:
  a: 1
Defensive patterns

Strategy: try-catch

Validate before calling

import yaml, json
text = path.read_text(encoding="utf-8")
try:
    json.loads(text)
except json.JSONDecodeError:
    yaml.safe_load(text)  # will surface the real parse error locally

Try / catch

try:
    data(path)
except ConversionError:
    # inspect the file with a local parser to see the true syntax error
    ...

Prevention

When it happens

Trigger: Calling data() on a file whose contents fail yaml.load with DataLoader or json parsing, or trigger RecursionError/TypeError (e.g. deeply nested aliases or exotic YAML tags).

Common situations: YAML with anchors/merge keys or custom tags; malformed JSON; files over the 32-level nesting limit; accidental binary content; wrong file extension for the actual format.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/f13fc8d7b3ae3eea. Report an issue: GitHub.

Appendix: source

Thrown at scripts/convert-plugin.py:80

        if json_only:
            value = json.loads(text, object_pairs_hook=unique_pairs,
                               parse_constant=lambda _: (_ for _ in ()).throw(ConversionError("Non-finite JSON number.")))
        else:
            depth = 0
            for event in yaml.parse(text):
                require(not isinstance(event, yaml.AliasEvent) and not getattr(event, "tag", None),
                        "YAML aliases and explicit tags (including !!js) are unsupported.")
                if isinstance(event, (yaml.MappingStartEvent, yaml.SequenceStartEvent)):
                    depth += 1
                    require(depth <= 32, "Configuration nesting exceeds 32 levels.")
                elif isinstance(event, (yaml.MappingEndEvent, yaml.SequenceEndEvent)):
                    depth -= 1
            value = yaml.load(text, Loader=DataLoader)
        check_data(value)
        return value
    except (yaml.YAMLError, json.JSONDecodeError, RecursionError, TypeError):
        # Parser errors can contain source lines and credentials. Do not echo them.
        raise ConversionError("Cannot parse portable data; use JSON for OpenCode or plain YAML/JSON for DSH.") from None


def check_data(value, depth=0):
    require(depth <= 32, "Configuration nesting exceeds 32 levels.")
    if isinstance(value, dict):
        mapping(value)
        require("__jsExpr" not in value, "DSH executable expressions require a manual port.")
        for child in value.values():
            check_data(child, depth + 1)
    elif isinstance(value, list):
        for child in value:
            check_data(child, depth + 1)
    else:
        require(value is None or type(value) in (str, int, float, bool), "Unsupported data type.")


def plain_path(path):
    """Reject links/reparse points in the supplied path, including ancestors."""

View on GitHub (pinned to 433685b202)