{"record":{"id":"eb7dcf7d17b1cb8e","repo":"fishaudio/fish-speech","slug":"reference-id-contains-invalid-characters-or-is-too","errorCode":null,"errorMessage":"Reference ID contains invalid characters or is too long. Only alphanumeric, hyphens, underscores, and spaces are allowed.","messagePattern":"Reference ID contains invalid characters or is too long\\. Only alphanumeric, hyphens, underscores, and spaces are allowed\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fish_speech/inference_engine/reference_loader.py","lineNumber":57,"sourceCode":"            backends = torchaudio.list_audio_backends()\n            if \"ffmpeg\" in backends:\n                self.backend = \"ffmpeg\"\n            else:\n                self.backend = \"soundfile\"\n        except AttributeError:\n            # torchaudio 2.9+ removed list_audio_backends()\n            # Try ffmpeg first, fallback to soundfile\n            try:\n                __import__(\"torchaudio.io._load_audio_fileobj\")\n\n                self.backend = \"ffmpeg\"\n            except (ImportError, ModuleNotFoundError):\n                self.backend = \"soundfile\"\n\n    @staticmethod\n    def _validate_id(id: str) -> None:\n        if not _ID_PATTERN.match(id) or len(id) > 255:\n            raise ValueError(\n                \"Reference ID contains invalid characters or is too long. \"\n                \"Only alphanumeric, hyphens, underscores, and spaces are allowed.\"\n            )\n\n    def load_by_id(\n        self,\n        id: str,\n        use_cache: Literal[\"on\", \"off\"],\n    ) -> Tuple:\n        self._validate_id(id)\n\n        # Load the references audio and text by id\n        ref_folder = Path(\"references\") / id\n        ref_folder.mkdir(parents=True, exist_ok=True)\n        ref_audios = list_files(\n            ref_folder, AUDIO_EXTENSIONS, recursive=True, sort=False\n        )\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/fishaudio/fish-speech/blob/befe4001745417f8c42131739d862b8a6fdbd15a/fish_speech/inference_engine/reference_loader.py#L39-L75","documentation":"ReferenceLoader validates user-supplied reference IDs against a regex (alphanumerics, hyphens, underscores, spaces) plus a 255-char length limit before using the ID as a directory name. An invalid ID raises ValueError, both as input validation and as path-traversal protection (blocking ../ and special characters).","triggerScenarios":"Calling load_by_id, add_reference, or delete_reference with an ID containing slashes, dots, unicode, or exceeding 255 characters — e.g. \"my/ref\" or \"spéaker!\".","commonSituations":"Using usernames, filenames, or free-form user input directly as reference IDs; IDs containing path separators cause this immediately as a security guard.","solutions":["Sanitize the ID: keep [A-Za-z0-9_- ] only and trim it","If the ID comes from user input, validate/normalize it before calling the API","For long IDs, use a hash or short slug instead"],"exampleFix":"# before\nloader.add_reference(\"../evil\", \"ref.wav\")  # ValueError\n\n# after\nimport re\nsafe = re.sub(r\"[^\\w\\- ]\", \"_\", user_id)[:255]\nloader.add_reference(safe, \"ref.wav\")","handlingStrategy":"validation","validationCode":"import re\n_ID_RE = re.compile(r\"^[A-Za-z0-9_-]+( [A-Za-z0-9_-]+)*$\")\n\ndef safe_id(s: str) -> str:\n    s = re.sub(r\"[^\\w\\- ]\", \"_\", s).strip()\n    if not _ID_RE.match(s) or len(s) > 255:\n        raise ValueError(\"bad id\")\n    return s","typeGuard":"import re\n\ndef is_valid_reference_id(id: str) -> bool:\n    return bool(re.match(r\"^[A-Za-z0-9_-]+( [A-Za-z0-9_-]+)*$\", id)) and len(id) <= 255","tryCatchPattern":"try:\n    loader.load_by_id(ref_id)\nexcept ValueError as e:\n    if \"invalid characters\" in str(e):\n        ref_id = re.sub(r\"[^\\w\\- ]\", \"_\", ref_id)[:255]\n        loader.load_by_id(ref_id)\n    else:\n        raise","preventionTips":["Generate IDs from a slugify function, never raw user input","Validate IDs at the API boundary before they reach ReferenceLoader"],"tags":["validation","sanitization","security","path-traversal"],"backgroundTag":"input-validation-failed","analyzedSha":"befe4001745417f8c42131739d862b8a6fdbd15a","analyzedAt":"2026-08-27T21:31:45.703Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}