fishaudio/fish-speech · error · ValueError

Unsupported part type: {part['type']}

Error message

Unsupported part type: {part['type']}

What it means

When a ContentSequence is constructed, any part given as a plain dict is converted to the appropriate part dataclass (VQPart, AudioPart, TextPart) based on its "type" key. If the dict's type is not one of these known types, the part cannot be mapped and a ValueError is raised.

Source

Thrown at fish_speech/content_sequence.py:105

        self: "ContentSequence",
        parts: list[BasePart | dict] | None = None,
        modality: Literal["text", "voice", "interleave"] | None = None,
        metadata: dict | None = None,
    ):
        self.modality = modality
        self.metadata = metadata or {}

        fixed_parts = []
        for part in parts or []:
            if isinstance(part, dict):
                if part["type"] == "vq":
                    part = VQPart(**part)
                elif part["type"] == "audio":
                    part = AudioPart(**part)
                elif part["type"] == "text":
                    part = TextPart(**part)
                else:
                    raise ValueError(f"Unsupported part type: {part['type']}")
            fixed_parts.append(part)

        self.parts = fixed_parts

        # If modality is specified, add it at the beginning if it's not already there
        if self.modality and not (
            len(self.parts) > 0
            and isinstance(self.parts[0], dict) is False
            and isinstance(self.parts[0], TextPart)
            and self.parts[0].text is not None
            and self.parts[0].text.startswith(MODALITY_TOKENS[self.modality])
        ):
            modality_token = MODALITY_TOKENS[self.modality]
            self.parts.insert(0, TextPart(text=modality_token))

    def append(
        self: "ContentSequence",
        part_or_parts: Union[BasePart, List[BasePart]],

View on GitHub (pinned to befe400174)

Solutions

  1. Check the accepted part types in content_sequence.py and fix the dict's type key (e.g. "vq", "audio", "text")
  2. If loading old serialized data, migrate/normalize the type field before constructing ContentSequence
  3. Pass part dataclass instances (VQPart/AudioPart/TextPart) instead of dicts to get type checking earlier

Example fix

# before
seq = ContentSequence(parts=[{"type": "image", "path": "x.png"}])

# after
seq = ContentSequence(parts=[{"type": "text", "text": "hello"}])
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_PART_TYPES = {"vq", "audio", "text"}

parts = [p for p in raw_parts if p.get("type") in ALLOWED_PART_TYPES] if all(isinstance(p, dict) for p in raw_parts) else raw_parts
seq = ContentSequence(parts=parts)

Type guard

def is_supported_part_dict(p) -> bool:
    return isinstance(p, dict) and p.get("type") in {"vq", "audio", "text"}

Try / catch

try:
    seq = ContentSequence(parts=raw_parts)
except ValueError as e:
    if "Unsupported part type" in str(e):
        # filter or migrate bad dicts, then retry
        ...
    raise

Prevention

When it happens

Trigger: Passing a dict part like {"type": "image", ...} or {"type": "vq_codes"} (misspelled) into ContentSequence(parts=[...]); any type key outside {vq, audio, text} (and whatever earlier branches accept).

Common situations: Loading serialized sequences from JSON where the schema changed between versions, typos in the type field, or hand-authored part dicts using wrong type names.

Related errors


AI-assisted analysis of fishaudio/fish-speech@befe400174 (2026-08-27). Data as JSON: /api/errors/c0b32fb92264c191. Report an issue: GitHub.