fishaudio/fish-speech · error · ValueError
Reference ID contains invalid characters or is too long. Onl
Error message
Reference ID contains invalid characters or is too long. Only alphanumeric, hyphens, underscores, and spaces are allowed.
What it means
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).
Source
Thrown at fish_speech/inference_engine/reference_loader.py:57
backends = torchaudio.list_audio_backends()
if "ffmpeg" in backends:
self.backend = "ffmpeg"
else:
self.backend = "soundfile"
except AttributeError:
# torchaudio 2.9+ removed list_audio_backends()
# Try ffmpeg first, fallback to soundfile
try:
__import__("torchaudio.io._load_audio_fileobj")
self.backend = "ffmpeg"
except (ImportError, ModuleNotFoundError):
self.backend = "soundfile"
@staticmethod
def _validate_id(id: str) -> None:
if not _ID_PATTERN.match(id) or len(id) > 255:
raise ValueError(
"Reference ID contains invalid characters or is too long. "
"Only alphanumeric, hyphens, underscores, and spaces are allowed."
)
def load_by_id(
self,
id: str,
use_cache: Literal["on", "off"],
) -> Tuple:
self._validate_id(id)
# Load the references audio and text by id
ref_folder = Path("references") / id
ref_folder.mkdir(parents=True, exist_ok=True)
ref_audios = list_files(
ref_folder, AUDIO_EXTENSIONS, recursive=True, sort=False
)
View on GitHub (pinned to befe400174)
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
Example fix
# before
loader.add_reference("../evil", "ref.wav") # ValueError
# after
import re
safe = re.sub(r"[^\w\- ]", "_", user_id)[:255]
loader.add_reference(safe, "ref.wav") Defensive patterns
Strategy: validation
Validate before calling
import re
_ID_RE = re.compile(r"^[A-Za-z0-9_-]+( [A-Za-z0-9_-]+)*$")
def safe_id(s: str) -> str:
s = re.sub(r"[^\w\- ]", "_", s).strip()
if not _ID_RE.match(s) or len(s) > 255:
raise ValueError("bad id")
return s Type guard
import re
def is_valid_reference_id(id: str) -> bool:
return bool(re.match(r"^[A-Za-z0-9_-]+( [A-Za-z0-9_-]+)*$", id)) and len(id) <= 255 Try / catch
try:
loader.load_by_id(ref_id)
except ValueError as e:
if "invalid characters" in str(e):
ref_id = re.sub(r"[^\w\- ]", "_", ref_id)[:255]
loader.load_by_id(ref_id)
else:
raise Prevention
- Generate IDs from a slugify function, never raw user input
- Validate IDs at the API boundary before they reach ReferenceLoader
When it happens
Trigger: 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!".
Common situations: Using usernames, filenames, or free-form user input directly as reference IDs; IDs containing path separators cause this immediately as a security guard.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Either text or tokens must be provided
- Unsupported part type: {part['type']}
- Unsupported part type: {type(part)}
- Unsupported audio format: {audio_path.suffix}. Supported for
AI-assisted analysis of fishaudio/fish-speech@befe400174 (2026-08-27).
Data as JSON: /api/errors/eb7dcf7d17b1cb8e.
Report an issue: GitHub.