langchain-ai/deepagents · error · FleetImportError

{source}: {_display_path(path)}: malformed tools.json: {exc.

Error message

{source}: {_display_path(path)}: malformed tools.json: {exc.msg}

What it means

A `tools.json` in the import (root or per-agent) is not valid JSON. The library parses it to compute MCP server requirements; a syntax error aborts the import, and the underlying `JSONDecodeError.msg` is surfaced with the archive and file path for diagnosis.

Source

Thrown at libs/talon/deepagents_talon/fleet_import.py:355

    paths: list[tuple[Path, str]] = []
    root = staging / "tools.json"
    if root.is_file():
        paths.append((root, "root"))
    agents = staging / "agents"
    if agents.is_dir():
        for child in sorted(agents.iterdir(), key=lambda item: item.name):
            path = child / "tools.json"
            if path.is_file():
                paths.append((path, child.name))
    return paths


def _load_tool_requests(path: Path, scope: str, source: Path) -> list[_ToolRequest]:
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except json.JSONDecodeError as exc:
        msg = f"{source}: {_display_path(path)}: malformed tools.json: {exc.msg}"
        raise FleetImportError(msg) from exc
    except OSError as exc:
        msg = f"{source}: {_display_path(path)}: {exc}"
        raise FleetImportError(msg) from exc
    if not isinstance(data, dict):
        msg = f"{source}: {_display_path(path)}: malformed tools.json: expected object"
        raise FleetImportError(msg)

    raw_tools = data.get("tools")
    if not isinstance(raw_tools, list):
        msg = f"{source}: {_display_path(path)}: malformed tools.json: expected tools list"
        raise FleetImportError(msg)
    interrupt_config = data.get("interrupt_config")
    interrupts = interrupt_config if isinstance(interrupt_config, dict) else {}

    requests: list[_ToolRequest] = []
    for index, item in enumerate(raw_tools):
        if not isinstance(item, dict):
            msg = f"{source}: {_display_path(path)}: tools[{index}] must be an object"

View on GitHub (pinned to a1af029e6e)

Solutions

  1. Validate the tools.json locally before zipping: `python -m json.tool tools.json` and fix the reported syntax issue (the message includes the exact `exc.msg`)
  2. Remove JSON-unfriendly constructs (comments, trailing commas); strip any UTF-8 BOM (`encoding="utf-8-sig"` source or re-save as plain UTF-8)
  3. Re-export the fleet if the file was corrupted in transit

Example fix

// before
{ 'tools': [], }  // single quotes, trailing comma
// after
{"tools": []}
Defensive patterns

Strategy: validation

Validate before calling

import json

def validate_tools_json(text):
    try:
        json.loads(text)
    except json.JSONDecodeError as exc:
        raise ValueError(f"tools.json invalid: {exc.msg} (line {exc.lineno}, col {exc.colno})") from exc

Type guard

def is_valid_json(text: str) -> bool:
    try:
        json.loads(text)
        return True
    except json.JSONDecodeError:
        return False

Try / catch

try:
    import_fleet_zip(zip_path, target_dir=target)
except FleetImportError as exc:
    if "malformed tools.json" in str(exc):
        print(f"Fix JSON syntax in tools.json: {exc}")
    raise

Prevention

When it happens

Trigger: `import_fleet_zip` → `_mcp_summaries` → `_load_tool_requests` runs `json.loads` on a staged `tools.json` and gets `json.JSONDecodeError`.

Common situations: Hand-edited tools.json with trailing commas or comments, single quotes instead of double quotes, BOM at file start, truncated file from a bad export, or template placeholders left unrendered.

Understand the failure class

Related errors


AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29). Data as JSON: /api/errors/a9af7b8213128b29. Report an issue: GitHub.