nexu-io/open-design · error · ValueError
slide_plan must be a non-empty JSON array of slides
Error message
slide_plan must be a non-empty JSON array of slides
What it means
Raised by load_plan in preview_outline_html.py when the JSON file at the given path does not reduce to a non-empty list of slides. The function accepts either a bare JSON array of slides OR an object with a `slides` key (a common wrapper shape), but after unwrapping the result must be a list with at least one element. Anything else — an object without `slides`, an empty array, a scalar, null — raises ValueError.
Source
Thrown at plugins/community/humanize-ppt/scripts/preview_outline_html.py:66
"takeaway": "收束",
}
ROLE_LEAVE_STATE = {
"hook": "注意力被抓住,愿意继续听",
"context": "共享背景成立,知道为什么是现在",
"tension": "意识到旧理解有缺口,想要答案",
"method": "看到一条可执行的路径",
"proof": "相信路径真实有效,不是口号",
"takeaway": "带走一句可复述的判断,知道下一步",
}
def load_plan(path):
data = json.loads(Path(path).read_text(encoding="utf-8"))
if isinstance(data, dict) and isinstance(data.get("slides"), list):
data = data["slides"]
if not isinstance(data, list) or not data:
raise ValueError("slide_plan must be a non-empty JSON array of slides")
return data
def state_rows(plan):
"""Chain per-slide enter/leave audience states from the role sequence."""
rows = []
enter = DECK_INITIAL_STATE
for slide in plan:
role = slide.get("role", "slide")
leave = ROLE_LEAVE_STATE.get(role, enter)
rows.append({
"slide_id": slide.get("slide_id", "?"),
"role": role,
"role_label": ROLE_LABELS.get(role, role),
"title": slide.get("title", ""),
"message": slide.get("message", ""),
"speaker_intent": slide.get("speaker_intent", ""),
"enter": enter,View on GitHub (pinned to 5be4028344)
Solutions
- Open the JSON file and confirm its top-level shape: `python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(type(d), len(d) if isinstance(d,(list,dict)) else '')" plan.json`.
- If the file is an object, ensure it has a non-empty `slides` array; if it has slides under a different key, restructure to `{"slides":[...]}` or a bare `[...]`.
- Re-run the upstream planner so it emits a non-empty array of slide objects.
- Validate the plan with a one-liner before invoking preview_outline_html: assert it is a list with len >= 1 and each entry is a dict.
Example fix
// before (plan.json contains {})
python3 preview_outline_html.py --plan plan.json
# -> ValueError: slide_plan must be a non-empty JSON array of slides
// after
# plan.json:
[{"slide_id":"s1","role":"hook","title":"..."}, {"slide_id":"s2","role":"tension","title":"..."}]
python3 preview_outline_html.py --plan plan.json Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
def load_plan_checked(path: str):
data = json.loads(Path(path).read_text(encoding="utf-8"))
if isinstance(data, dict) and isinstance(data.get("slides"), list):
data = data["slides"]
if not isinstance(data, list) or not data:
raise SystemExit(
f"Plan must be a non-empty array of slides (got "
f"{type(data).__name__}, len={len(data) if hasattr(data,'__len__') else 'n/a'})."
)
if not all(isinstance(s, dict) for s in data):
raise SystemExit("Each slide must be a JSON object.")
return data Type guard
def is_slide_plan(data) -> bool:
if isinstance(data, dict):
data = data.get("slides")
return isinstance(data, list) and len(data) > 0 and all(isinstance(s, dict) for s in data) Try / catch
try:
plan = load_plan(plan_path)
except ValueError as exc:
raise SystemExit(f"Invalid slide plan: {exc}") from exc Prevention
- Define and validate the plan JSON schema (jsonschema or pydantic) before rendering.
- Ensure the upstream planner always emits a non-empty list (or {slides: [...]}).
- Add a unit test on load_plan covering empty array, dict-without-slides, scalar, and null.
- Refuse to proceed past plan loading until the shape is confirmed.
When it happens
Trigger: Passing a JSON file that is `{}` or `{"meta": ...}` without a slides array; an empty `[]`; a file containing a single slide object instead of an array; malformed/placeholder JSON produced by a half-finished pipeline stage; wrong file handed to the script (a config JSON instead of a plan JSON).
Common situations: Upstream slide-planning step wrote a status object instead of a plan; LLM produced a single slide dict rather than an array; user passed the deck spec where the outline plan was expected; empty plan from a filtering step that removed every slide.
Related errors
- invalid JSON in ${filePath}: ${message}
- ${filePath} must contain a JSON object
- proposal patch.after is not valid JSON
- brand.json is not valid JSON.
- authorized pull response must be an object
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/278a09e3a81eaf0f.
Report an issue: GitHub.