{"record":{"id":"4cd2f7d62091a09e","repo":"PaddlePaddle/PaddleOCR","slug":"decoder-start-token-id-expected-to-have-length","errorCode":null,"errorMessage":"`decoder_start_token_id` expected to have length {batch_size} but got {len(decoder_start_token_id)}","messagePattern":"`decoder_start_token_id` expected to have length (.+?) but got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"ppocr/modeling/heads/rec_ppformulanet_head.py","lineNumber":992,"sourceCode":"    ):\n\n        # 1. Check whether the user has defined `decoder_input_ids` manually. To facilitate in terms of input naming,\n        # we also allow the user to pass it under `input_ids`, if the encoder does not use it as the main input.\n        if model_kwargs is not None and \"decoder_input_ids\" in model_kwargs:\n            decoder_input_ids = model_kwargs.pop(\"decoder_input_ids\")\n        elif \"input_ids\" in model_kwargs:\n            decoder_input_ids = model_kwargs.pop(\"input_ids\")\n        else:\n            decoder_input_ids = None\n\n        # 2. Encoder-decoder models expect the `decoder_input_ids` to start with a special token. Let's ensure that.\n        decoder_start_token_id = self._get_decoder_start_token_id(\n            decoder_start_token_id, bos_token_id\n        )\n\n        if isinstance(decoder_start_token_id, list):\n            if len(decoder_start_token_id) != batch_size:\n                raise ValueError(\n                    f\"`decoder_start_token_id` expected to have length {batch_size} but got {len(decoder_start_token_id)}\"\n                )\n            decoder_input_ids_start = paddle.to_tensor(\n                decoder_start_token_id,\n                dtype=paddle.int64,\n            )\n            decoder_input_ids_start = decoder_input_ids_start.view(-1, 1)\n        else:\n            use_parallel = self.config_decoder.use_parallel\n            parallel_step = self.config_decoder.parallel_step\n\n            if use_parallel:\n                decoder_input_ids_start = (\n                    paddle.ones(\n                        (batch_size, parallel_step),\n                        dtype=paddle.int64,\n                    )\n                    * decoder_start_token_id","sourceCodeStart":974,"sourceCodeEnd":1010,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_ppformulanet_head.py#L974-L1010","documentation":"In generation, when decoder_start_token_id is provided as a list, the code builds one start token per sequence and therefore requires len(list) == batch_size. A list of any other length raises ValueError.","triggerScenarios":"Calling generate with decoder_start_token_id as a list whose length differs from the batch dimension of input_ids/inputs_embeds — e.g. 4 start ids for a batch of 2, or a single-element list where batch > 1.","commonSituations":"Prompt-specific start tokens (per-sample BOS) where the list wasn't padded/trimmed to batch size; passing a scalar wrapped in [token] while running batched inference; dynamic batching upstream while the start-id list stays fixed.","solutions":["Make the list length equal batch_size, one start id per sample (or broadcast a single value)","If all samples share the same start token, pass the plain int decoder_start_token_id instead of a list","Compute the list from your batch at runtime: [start_for(sample) for sample in batch]"],"exampleFix":"# before\nout = model.generate(input_ids=x, decoder_start_token_id=[0])  # batch is 4\n# after\nbs = x.shape[0]\nout = model.generate(input_ids=x, decoder_start_token_id=[0]*bs)","handlingStrategy":"validation","validationCode":"def normalize_start_ids(decoder_start_token_id, batch_size):\n    if isinstance(decoder_start_token_id, (list, tuple)):\n        if len(decoder_start_token_id) != batch_size:\n            raise ValueError(f'start ids len {len(decoder_start_token_id)} != batch {batch_size}')\n        return list(decoder_start_token_id)\n    return decoder_start_token_id","typeGuard":"def start_ids_match_batch(v, batch) -> bool:\n    return not isinstance(v, (list, tuple)) or len(v) == batch","tryCatchPattern":"try:\n    out = model.generate(input_ids=x, decoder_start_token_id=start)\nexcept ValueError as e:\n    if 'decoder_start_token_id' in str(e) and isinstance(start, (list, tuple)):\n        out = model.generate(input_ids=x, decoder_start_token_id=start[0])  # shared start token\n    else:\n        raise","preventionTips":["Pass a scalar start token when all samples share one","Compute per-sample lists from the actual batch at runtime","Add a batch-assert before generate in inference wrappers"],"tags":["generation","batch-mismatch","ppformulanet"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}