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
- 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`)
- Remove JSON-unfriendly constructs (comments, trailing commas); strip any UTF-8 BOM (`encoding="utf-8-sig"` source or re-save as plain UTF-8)
- 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
- Run `python -m json.tool tools.json` before zipping
- Never hand-edit JSON without re-validating
- Save files as plain UTF-8 without BOM
- Generate tools.json programmatically (json.dump) instead of string templates
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid MCP config at {mcp_config_path}: {exc}
- {source}: {_display_path(path)}: malformed tools.json: expec
- {source}: {_display_path(path)}: malformed tools.json: expec
- {source}: {_display_path(path)}: tools[{index}] must be an o
- {source}: {_display_path(path)}: tools[{index}].{key} must b
AI-assisted analysis of langchain-ai/deepagents@a1af029e6e (2026-08-29).
Data as JSON: /api/errors/a9af7b8213128b29.
Report an issue: GitHub.