fishaudio/fish-speech · error · ValueError
Unsupported part type: {type(part)}
Error message
Unsupported part type: {type(part)} What it means
ContentSequence.encode walks over self.parts and encodes each part (text parts are tokenized, VQ parts produce semantic tokens). If a part is neither a TextPart, VQPart, AudioPart, nor other handled isinstance branch, encode has no encoding strategy and raises ValueError naming the offending type.
Source
Thrown at fish_speech/content_sequence.py:214
tokens = tokenizer.encode(part.text, add_special_tokens=False)
else:
tokens = part.tokens
tokens = torch.tensor(tokens, dtype=torch.long)
elif isinstance(part, VQPart):
# Critical Optimization: Vectorized mapping
# Instead of loop lookup: [tokenizer.semantic_id_to_token_id[i] for i in codes]
# We use arithmetic offset: code + semantic_begin_id
# This assumes semantic tokens are contiguous in the vocab (DualAR requirement)
curr_codes = part.codes.clone().to(torch.int)
# Use int64 (long) for token IDs to avoid overflow or type mismatch in embedding
tokens = (curr_codes[0] + tokenizer.semantic_begin_id).to(torch.long)
vq_parts.append(curr_codes)
vq_require_losses.append(part.cal_loss)
else:
raise ValueError(f"Unsupported part type: {type(part)}")
all_tokens.append(tokens)
# Set masks for different part types
if isinstance(part, VQPart):
vq_masks.append(torch.ones_like(tokens, dtype=torch.bool))
audio_masks.append(torch.zeros_like(tokens, dtype=torch.bool))
elif isinstance(part, AudioPart):
vq_masks.append(torch.zeros_like(tokens, dtype=torch.bool))
audio_mask = torch.ones_like(tokens, dtype=torch.bool)
audio_mask[0] = False # Skip start token
audio_mask[-1] = False # Skip end token
audio_masks.append(audio_mask)
else:
vq_masks.append(torch.zeros_like(tokens, dtype=torch.bool))
audio_masks.append(torch.zeros_like(tokens, dtype=torch.bool))
# Set labels based on whether we want to calculate loss for this partView on GitHub (pinned to befe400174)
Solutions
- Ensure all parts are instances of the supported dataclasses (TextPart/VQPart/AudioPart) before calling encode
- Construct the sequence through ContentSequence(...) so dicts are normalized in __init__
- If you defined a custom part type, extend/patch encode() to handle it via isinstance dispatch
Example fix
# before
seq.parts.append({"type": "text", "text": "hi"})
seq.encode(...)
# after
seq.parts.append(TextPart(text="hi"))
seq.encode(...) Defensive patterns
Strategy: type-guard
Validate before calling
from fish_speech.content_sequence import TextPart, VQPart, AudioPart SUPPORTED = (TextPart, VQPart, AudioPart) assert all(isinstance(p, SUPPORTED) for p in seq.parts), "unencoded part present"
Type guard
from fish_speech.content_sequence import TextPart, VQPart, AudioPart
def is_encodable(part) -> bool:
return isinstance(part, (TextPart, VQPart, AudioPart)) Try / catch
try:
encoded = seq.encode(...)
except ValueError as e:
if "Unsupported part type" in str(e):
bad = [p for p in seq.parts if not isinstance(p, (TextPart, VQPart, AudioPart))]
raise RuntimeError(f"bad parts: {bad}") from e
raise Prevention
- Only append typed part objects to .parts; never raw dicts
- If subclassing parts, also extend encode()'s dispatch
When it happens
Trigger: Calling ContentSequence.encode() (directly or via encode_for_inference/visualize) when parts contains a raw dict that wasn't normalized (constructed by bypassing __init__ fixes), a None, or a custom/BasePart subclass that encode() doesn't handle.
Common situations: Appending parts to an existing sequence's .parts list directly, subclassing BasePart without extending encode(), or storing plain dicts in parts after object creation.
Related errors
- Either text or tokens must be provided
- Unsupported part type: {part['type']}
- Unsupported audio format: {audio_path.suffix}. Supported for
- {i} is not a file or directory
- Expected GenerateResponse, got {type(wrapped_result.response
AI-assisted analysis of fishaudio/fish-speech@befe400174 (2026-08-27).
Data as JSON: /api/errors/5592bf276e61e78c.
Report an issue: GitHub.