{"record":{"id":"986a806a221a4e0b","repo":"PaddlePaddle/PaddleOCR","slug":"is-not-supported-in-multihead-yet","errorCode":null,"errorMessage":"{} is not supported in MultiHead yet","messagePattern":"(.+?) is not supported in MultiHead yet","errorType":"exception","errorClass":"NotImplementedError","httpStatus":null,"severity":"error","filePath":"ppocr/modeling/heads/rec_multi_head.py","lineNumber":130,"sourceCode":"                    out_channels=out_channels_list[\"NRTRLabelDecode\"],\n                )\n            elif name == \"CTCHead\":\n                # ctc neck\n                self.encoder_reshape = Im2Seq(in_channels)\n                neck_args = self.head_list[idx][name][\"Neck\"]\n                encoder_type = neck_args.pop(\"name\")\n                self.ctc_encoder = SequenceEncoder(\n                    in_channels=in_channels, encoder_type=encoder_type, **neck_args\n                )\n                # ctc head\n                head_args = self.head_list[idx][name][\"Head\"]\n                self.ctc_head = eval(name)(\n                    in_channels=self.ctc_encoder.out_channels,\n                    out_channels=out_channels_list[\"CTCLabelDecode\"],\n                    **head_args,\n                )\n            else:\n                raise NotImplementedError(\n                    \"{} is not supported in MultiHead yet\".format(name)\n                )\n\n    def forward(self, x, targets=None):\n        if self.use_pool:\n            x = self.pool(\n                x.reshape([0, 3, -1, self.in_channels]).transpose([0, 3, 1, 2])\n            )\n        ctc_encoder = self.ctc_encoder(x)\n        ctc_out = self.ctc_head(ctc_encoder, targets)\n        head_out = dict()\n        head_out[\"ctc\"] = ctc_out\n        head_out[\"ctc_neck\"] = ctc_encoder\n        # eval mode\n        if not self.training:\n            return ctc_out\n        if self.gtc_head == \"sar\":\n            sar_out = self.sar_head(x, targets[1:])","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_multi_head.py#L112-L148","documentation":"MultiHead is a composite head that builds a CTC branch (plus optional SAR/NRTR branch) by dispatching on the name key of each entry in the config's Head list. Only known names take a dedicated construction path; any other name reaches the else and raises NotImplementedError.","triggerScenarios":"Configuring Multi with a Head list whose name is neither \"Multi\" nor \"SRNHead\" (those are the two dispatched names in __init__), e.g. name: \"CTCHead\", \"NRHead\", \"Multi1\", or a typo like \"multi\".","commonSituations":"Converting a single-head rec config to the Multi template and leaving the old head name in place; renaming heads during an upgrade; YAML indentation putting the name key at the wrong level so it is read as an unknown value.","solutions":["Set each entry's name to \"Multi\" (CTC + optional SAR) or \"SRNHead\" exactly as MultiHead expects; check the canonical Multi config templates under configs/rec for the exact structure","If you genuinely need a new head type inside MultiHead, add an elif branch in ppocr/modeling/heads/rec_multi_head.py that constructs it, mirroring the SRNHead path","Print self.head_list in __init__ to confirm the parsed structure matches what you wrote in YAML"],"exampleFix":"# before (config yml)\nHead:\n  name: Multi\n  Head list:\n    - name: CTCHead   # not supported\n      Head: ...\n# after\nHead:\n  name: Multi\n  Head list:\n    - name: Multi     # CTC branch built by SequenceEncoder path\n      Head: ...\n    - name: SARHead\n      Head: ...","handlingStrategy":"validation","validationCode":"SUPPORTED = {\"Multi\", \"SRNHead\"}\ndef validate_head_list(head_list):\n    names = [entry.get('name') if isinstance(entry, dict) else entry for entry in head_list]\n    bad = [n for n in names if n not in SUPPORTED]\n    if bad:\n        raise ValueError(f'MultiHead does not support head names {bad}; supported: {sorted(SUPPORTED)}')","typeGuard":"def is_supported_head_name(name) -> bool:\n    return isinstance(name, str) and name in {'Multi', 'SRNHead'}","tryCatchPattern":"try:\n    model = build_model(cfg)\nexcept NotImplementedError as e:\n    if 'not supported in MultiHead' in str(e):\n        raise ValueError(f'check Head list names in config: {e}') from e\n    raise","preventionTips":["Start from an official Multi config template and only edit values, not names","Assert head-list names against the supported set in a config unit test","Beware YAML indentation: 'name' must sit under each Head-list entry"],"tags":["config","multi-head","recognition","api-misuse"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}