{"record":{"id":"01bbd8422cee2e5e","repo":"twentyhq/twenty","slug":"duplicate-key-found-in-json-key","errorCode":null,"errorMessage":"Duplicate key found in JSON: '{key}'","messagePattern":"Duplicate key found in JSON: '(.+?)'","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"packages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/replace.py","lineNumber":209,"sourceCode":"                                first_text += \"...\"\n                            unused_with_content.append(f\"{k} ('{first_text}')\")\n                        else:\n                            unused_with_content.append(k)\n\n                errors.append(\n                    f\"Shape '{shape_key}' not found on '{slide_key}'. \"\n                    f\"Shapes without replacements: {', '.join(sorted(unused_with_content)) if unused_with_content else 'none'}\"\n                )\n\n    return errors\n\n\ndef check_duplicate_keys(pairs):\n    \"\"\"Check for duplicate keys when loading JSON.\"\"\"\n    result = {}\n    for key, value in pairs:\n        if key in result:\n            raise ValueError(f\"Duplicate key found in JSON: '{key}'\")\n        result[key] = value\n    return result\n\n\ndef apply_replacements(pptx_file: str, json_file: str, output_file: str):\n    \"\"\"Apply text replacements from JSON to PowerPoint presentation.\"\"\"\n\n    # Load presentation\n    prs = Presentation(pptx_file)\n\n    # Get inventory of all text shapes (returns ShapeData objects)\n    # Pass prs to use same Presentation instance\n    inventory = extract_text_inventory(Path(pptx_file), prs)\n\n    # Detect text overflow in original presentation\n    original_overflow = detect_frame_overflow(inventory)\n\n    # Load replacement data with duplicate key detection","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/twentyhq/twenty/blob/1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6/packages/twenty-server/src/engine/core-modules/code-interpreter/sandbox-scripts/pptx/replace.py#L191-L227","documentation":"Raised by the object_pairs_hook `check_duplicate_keys` passed to json.load when parsing the replacement JSON in replace.py. Because Python's default dict silently overwrites duplicate keys, the hook makes a duplicate key a hard error so a replacement file cannot accidentally shadow an earlier mapping for the same shape/slide.","triggerScenarios":"The replacement JSON contains the same key twice at the same nesting level — e.g. two `slide-1` entries, or two shape keys under the same slide. This typically comes from hand-editing or from an LLM concatenating partial replacement blocks without dedup.","commonSituations":"An LLM in the code-interpreter merges two inventory-driven replacement drafts into one JSON and forgets to dedupe; a templating step emits a key per source without grouping; copy-paste of a shape block that retains the original key.","solutions":["Open the replacement JSON and find the duplicated key named in the message; merge or rename the conflicting entry.","Validate the JSON with a linter that flags duplicate keys (e.g. `python -c` using the same object_pairs_hook) before passing it to apply_replacements.","When generating replacements programmatically, accumulate into a dict so later writes overwrite deterministically, then serialize once."],"exampleFix":"// before — replacement.json has two \"slide-1\" keys\n{\n  \"slide-1\": { \"title\": \"A\" },\n  \"slide-1\": { \"subtitle\": \"B\" }\n}\n// after — merged under one key\n{\n  \"slide-1\": { \"title\": \"A\", \"subtitle\": \"B\" }\n}","handlingStrategy":"validation","validationCode":"import json\n\ndef load_replacements_strict(path: str) -> dict:\n    with open(path) as f:\n        return json.load(f, object_pairs_hook=check_duplicate_keys)\n\n# Pre-flight: lint the file before the tool runs\ntry:\n    load_replacements_strict('replacements.json')\nexcept ValueError as e:\n    print(f'Fix duplicate keys first: {e}')\n    raise","typeGuard":"def has_no_duplicate_keys(pairs) -> bool:\n    seen = set()\n    for k, _ in pairs:\n        if k in seen:\n            return False\n        seen.add(k)\n    return True","tryCatchPattern":"try:\n    replacements = json.load(f, object_pairs_hook=check_duplicate_keys)\nexcept ValueError as e:\n    if 'Duplicate key' in str(e):\n        # surface the key name and the file path to the operator, then abort\n        raise ValueError(f'{path}: {e}. Merge or rename the duplicate before retrying.') from e\n    raise","preventionTips":["Generate replacement JSON by building a dict in memory and serializing once — later writes overwrite deterministically with no duplicates emitted.","Lint replacement files with the same object_pairs_hook before passing them to apply_replacements.","When merging two replacement drafts, dedupe by key before serializing."],"tags":["python","pptx","code-interpreter","json-validation","duplicate-key"],"backgroundTag":null,"analyzedSha":"1f5dd2bbd2a8da3419c8cfd52dd545c0024df1a6","analyzedAt":"2026-08-12T15:37:27.593Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}