twentyhq/twenty · error · ValueError
Found {len(errors)} validation error(s)
Error message
Found {len(errors)} validation error(s) What it means
Raised by apply_replacements in replace.py after validate_replacements returns a non-empty error list. validate_replacements checks every shape referenced in the replacement JSON against the inventory of actual text shapes on the deck; any shape_key or slide_key that does not exist, or shapes on the slide that were left without a replacement when the file intended full coverage, becomes an error. The throw halts before any slide is mutated.
Source
Thrown at packages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/replace.py:241
# Detect text overflow in original presentation
original_overflow = detect_frame_overflow(inventory)
# Load replacement data with duplicate key detection
with open(json_file, "r") as f:
replacements = json.load(f, object_pairs_hook=check_duplicate_keys)
# Validate replacements
errors = validate_replacements(inventory, replacements)
if errors:
print("ERROR: Invalid shapes in replacement JSON:")
for error in errors:
print(f" - {error}")
print("\nPlease check the inventory and update your replacement JSON.")
print(
"You can regenerate the inventory with: python inventory.py <input.pptx> <output.json>"
)
raise ValueError(f"Found {len(errors)} validation error(s)")
# Track statistics
shapes_processed = 0
shapes_cleared = 0
shapes_replaced = 0
# Process each slide from inventory
for slide_key, shapes_dict in inventory.items():
if not slide_key.startswith("slide-"):
continue
slide_index = int(slide_key.split("-")[1])
if slide_index >= len(prs.slides):
print(f"Warning: Slide {slide_index} not found")
continue
# Process each shape from inventoryView on GitHub (pinned to 1f5dd2bbd2)
Solutions
- Read the printed error list — each line names the offending slide/shape and what was expected.
- Regenerate the inventory with `python inventory.py <input.pptx> <inventory.json>` and align your replacement keys to the current shape names.
- If you only want to replace some shapes, ensure your replacement file's intent matches what validate_replacements expects (see its unused-shape handling).
- Re-run apply_replacements once every reported shape key exists in the inventory.
Example fix
# before — replacement references shape 'Subtitle' that no longer exists python replace.py deck.pptx bad_replacements.json out.pptx # after — regenerate inventory, then rebuild replacements against real shape names python inventory.py deck.pptx inventory.json # edit replacements.json to use the keys inventory.json lists, then: python replace.py deck.pptx replacements.json out.pptx
Defensive patterns
Strategy: validation
Validate before calling
import json
from inventory import build_inventory
def prevalidate_replacements(pptx_path: str, replacements_path: str) -> list[str]:
inventory = build_inventory(pptx_path)
with open(replacements_path) as f:
replacements = json.load(f, object_pairs_hook=check_duplicate_keys)
return validate_replacements(inventory, replacements) # returns [] when clean Type guard
def replacements_are_clean(inventory: dict, replacements: dict) -> bool:
return not validate_replacements(inventory, replacements) Try / catch
try:
apply_replacements(pptx, replacements_json, output)
except ValueError as e:
if 'validation error' in str(e):
# errors already printed to stdout; regenerate inventory and prompt for a fixed file
run_inventory(pptx, 'inventory.json')
raise SystemExit('Replacements did not match inventory. See errors above; inventory.json regenerated.')
raise Prevention
- Regenerate the inventory immediately before building replacements so shape names match the current deck.
- Run validate_replacements as a pre-flight and refuse to proceed on any error.
- Treat shape keys as opaque identifiers from the inventory — never hand-type them.
When it happens
Trigger: The replacement JSON references a shape name that does not exist on the named slide, references a slide key (slide-N) whose N is out of range, or — when the replacement file was meant to cover all content shapes — leaves shapes un-replaced. The detailed per-error list is printed to stdout just before the throw.
Common situations: An LLM edits an old replacement JSON after the deck changed (shapes renamed/reordered); a replacement file built from one deck is reused on another; typos in shape keys; a partial replacement intended for a few shapes but run in strict-full-coverage mode.
Related errors
- Slide index {idx} out of range (0-{total_slides - 1})
- Found {len(overflow_errors)} overflow error(s) and {len(warn
- {input_dir} is not a directory
- {output_file} must be a .docx, .pptx, or .xlsx file
- Duplicate key found in JSON: '{key}'
AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12).
Data as JSON: /api/errors/19f4ef11a514c4c8.
Report an issue: GitHub.