{"record":{"id":"2fbcbdd475caf018","repo":"fishaudio/fish-speech","slug":"reference-id-id-already-exists","errorCode":null,"errorMessage":"Reference ID '{id}' already exists","messagePattern":"Reference ID '(.+?)' already exists","errorType":"validation","errorClass":"FileExistsError","httpStatus":null,"severity":"error","filePath":"fish_speech/inference_engine/reference_loader.py","lineNumber":209,"sourceCode":"        \"\"\"\n        Add a new reference voice by creating a new directory and copying files.\n\n        Args:\n            id: Reference ID (directory name)\n            wav_file_path: Path to the audio file to copy\n            reference_text: Text content for the .lab file\n\n        Raises:\n            FileExistsError: If the reference ID already exists\n            FileNotFoundError: If the audio file doesn't exist\n            OSError: If file operations fail\n        \"\"\"\n        self._validate_id(id)\n\n        # Check if reference already exists\n        ref_dir = Path(\"references\") / id\n        if ref_dir.exists():\n            raise FileExistsError(f\"Reference ID '{id}' already exists\")\n\n        # Check if audio file exists\n        audio_path = Path(wav_file_path)\n        if not audio_path.exists():\n            raise FileNotFoundError(f\"Audio file not found: {wav_file_path}\")\n\n        # Validate audio file extension\n        if audio_path.suffix.lower() not in AUDIO_EXTENSIONS:\n            raise ValueError(\n                f\"Unsupported audio format: {audio_path.suffix}. Supported formats: {', '.join(AUDIO_EXTENSIONS)}\"\n            )\n\n        try:\n            # Create reference directory\n            ref_dir.mkdir(parents=True, exist_ok=False)\n\n            # Determine the target audio filename with original extension\n            target_audio_path = ref_dir / f\"sample{audio_path.suffix}\"","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/fishaudio/fish-speech/blob/befe4001745417f8c42131739d862b8a6fdbd15a/fish_speech/inference_engine/reference_loader.py#L191-L227","documentation":"add_reference stores each voice reference under references/<id>/. If that directory already exists, the ID is taken and a FileExistsError is raised before any file is written, preventing silent overwrites of existing references.","triggerScenarios":"Calling add_reference(id=...) twice with the same ID (even if the wav differs), or re-running a script that registers references after a previous partial/complete run.","commonSituations":"Re-running ingestion scripts without cleanup, retrying after a failure that had already created the directory (mkdir with exist_ok=False happens later, but this check fires first).","solutions":["Use delete_reference(id) first, then add_reference again","Choose a unique ID (append a suffix/version, e.g. \"speaker_v2\")","Wrap add_reference in try/except FileExistsError for idempotent ingestion scripts"],"exampleFix":"# before\nloader.add_reference(\"my_voice\", \"a.wav\")  # FileExistsError on second run\n\n# after\ntry:\n    loader.add_reference(\"my_voice\", \"a.wav\")\nexcept FileExistsError:\n    loader.delete_reference(\"my_voice\")\n    loader.add_reference(\"my_voice\", \"a.wav\")","handlingStrategy":"try-catch","validationCode":"from pathlib import Path\nif (Path(\"references\") / ref_id).exists():\n    print(f\"reference '{ref_id}' already registered; skipping or replacing\")","typeGuard":null,"tryCatchPattern":"try:\n    loader.add_reference(ref_id, wav)\nexcept FileExistsError:\n    loader.delete_reference(ref_id)\n    loader.add_reference(ref_id, wav)","preventionTips":["Make ingestion scripts idempotent: check-then-add or catch FileExistsError","Version reference IDs instead of reusing names"],"tags":["conflict","idempotency","file-exists","python"],"backgroundTag":"duplicate-resource-conflict","analyzedSha":"befe4001745417f8c42131739d862b8a6fdbd15a","analyzedAt":"2026-08-27T21:31:45.703Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}