nexu-io/open-design · error · ValueError

Generated chatSpec.ts has an unexpected shape

Error message

Generated chatSpec.ts has an unexpected shape

What it means

Thrown by read_generated_chat_spec() in run_test_matrix.py when the generated src/chatSpec.ts file does not start with 'export const chatSpec = ' or does not end with ' as const;'. The test harness strips those wrappers to recover the JSON object, so any deviation (manual edit, different template, partial write) makes parsing impossible.

Source

Thrown at skills/chat-motion-overlay/scripts/run_test_matrix.py:34

    parser.add_argument("--node-modules", required=True, help="Resolved node_modules directory with remotion/react/typescript")
    parser.add_argument("--render", action="store_true", help="Render representative still frames with Remotion")
    return parser.parse_args()


def write_json(path: Path, payload: dict) -> None:
    path.write_text(json.dumps(payload, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def run(cmd: list[str], cwd: Path) -> subprocess.CompletedProcess[str]:
    return subprocess.run(cmd, cwd=str(cwd), text=True, capture_output=True)


def read_generated_chat_spec(path: Path) -> dict:
    content = path.read_text(encoding="utf-8").strip()
    prefix = "export const chatSpec = "
    suffix = " as const;"
    if not content.startswith(prefix) or not content.endswith(suffix):
        raise ValueError("Generated chatSpec.ts has an unexpected shape")
    return json.loads(content[len(prefix) : -len(suffix)])


def participant(side: str, preset: str, upload_path: str | None = None) -> dict:
    value = {"side": side, "preset": preset}
    if upload_path:
        value["uploadPath"] = upload_path
    return value


def base_config(
    *,
    container: str = "wechat",
    avatar_mode: str = "preset",
    device_frame: str = "iphone-dynamic-island",
    nickname_mode: str = "hidden",
    delivery_format: str = "mov",
    show_timestamp: bool = True,

View on GitHub (pinned to 5be4028344)

Solutions

  1. Regenerate the bundle with prepare_chat_overlay_bundle.py so chatSpec.ts is written by write_chat_spec_ts in the canonical shape.
  2. If you intentionally changed the wrapper, update read_generated_chat_spec's prefix/suffix constants to match.
  3. Ensure run_test_matrix.py reads from a bundle this tool generated, not a manually authored file.

Example fix

// before (chatSpec.ts after a hand edit)
export const chatSpec: ChatSpec = {...};
// after (regenerated)
export const chatSpec = { ... } as const;
Defensive patterns

Strategy: type-guard

Validate before calling

PREFIX = "export const chatSpec = "
SUFFIX = " as const;"
def safe_read_chat_spec(path):
    content = path.read_text(encoding="utf-8").strip()
    if not content.startswith(PREFIX) or not content.endswith(SUFFIX):
        raise ValueError("chatSpec.ts shape mismatch; regenerate the bundle")
    import json
    return json.loads(content[len(PREFIX):-len(SUFFIX)])

Type guard

def is_canonical_chat_spec_ts(content: str) -> bool:
    c = content.strip()
    return c.startswith("export const chatSpec = ") and c.endswith(" as const;")

Prevention

When it happens

Trigger: run_test_matrix.py reads <bundle>/src/chatSpec.ts after prepare_chat_overlay_bundle.py produced it, but the file's shape changed — e.g. the template was hand-edited, write_chat_spec_ts was modified to emit a different wrapper, or a stale/foreign chatSpec.ts is present.

Common situations: Editing the remotion template's chatSpec.ts by hand; changing the wrapper format in write_chat_spec_ts without updating the reader; pointing the test matrix at a bundle produced by an older or forked template.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/8bb1346a6efdc797. Report an issue: GitHub.