{"record":{"id":"1253102f5330f554","repo":"docling-project/docling","slug":"neither-processor-batch-decode-nor-tokenizer-batch-125310","errorCode":null,"errorMessage":"Neither processor.batch_decode nor tokenizer.batch_decode is available.","messagePattern":"Neither processor\\.batch_decode nor tokenizer\\.batch_decode is available\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"docling/models/vlm_pipeline_models/hf_transformers_model.py","lineNumber":399,"sourceCode":"            gen_kwargs[\"do_sample\"] = False\n\n        if stopping_criteria is not None:\n            gen_kwargs[\"stopping_criteria\"] = stopping_criteria\n\n        start_time = time.time()\n        with torch.inference_mode():\n            generated_ids = self.vlm_model.generate(**gen_kwargs)\n        generation_time = time.time() - start_time\n\n        input_len = inputs[\"input_ids\"].shape[1]  # common right-aligned prompt length\n        trimmed_sequences = generated_ids[:, input_len:]  # only newly generated tokens\n\n        # -- Decode with the processor/tokenizer (skip specials, keep DocTags as text)\n        decode_fn = getattr(self.processor, \"batch_decode\", None)\n        if decode_fn is None and getattr(self.processor, \"tokenizer\", None) is not None:\n            decode_fn = self.processor.tokenizer.batch_decode\n        if decode_fn is None:\n            raise RuntimeError(\n                \"Neither processor.batch_decode nor tokenizer.batch_decode is available.\"\n            )\n\n        decoded_texts: list[str] = decode_fn(\n            trimmed_sequences,\n            **decoder_config,\n        )\n\n        # -- Clip off pad tokens from decoded texts\n        pad_token = self.processor.tokenizer.pad_token\n        if pad_token:\n            decoded_texts = [text.rstrip(pad_token) for text in decoded_texts]\n\n        if (\n            self.vlm_options.extra_generation_config.get(\"strip_stop_strings\", False)\n            and self.vlm_options.stop_strings\n        ):\n            from docling.utils.vlm_utils import strip_stop_strings","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/vlm_pipeline_models/hf_transformers_model.py#L381-L417","documentation":"After generate(), the model decodes token IDs via processor.batch_decode, falling back to processor.tokenizer.batch_decode. If the loaded processor exposes neither (some vision processors wrap the tokenizer under different attribute names), RuntimeError is raised because decoded text cannot be produced.","triggerScenarios":"Loading a newer/less-common processor whose tokenizer is stored under an attribute other than 'tokenizer' and which does not itself implement batch_decode, then running a conversion that reaches generation.","commonSituations":"Upgrading transformers so a processor class changes its attribute layout; using an experimental repo_id whose processor is minimally implemented; mismatches between processor and tokenizer versions in a custom env.","solutions":["Prefer a repo_id whose processor exposes batch_decode or a .tokenizer attribute (standard HF vision-language processors)","Before converting, attach the real tokenizer: model.processor.tokenizer = model.processor.<actual_tokenizer_attr>","If the processor is fundamentally incompatible, use the vLLM engine for that model, which handles decoding itself"],"exampleFix":"# before: processor has .tokenizer_wrapper but no .tokenizer\n# RuntimeError: Neither processor.batch_decode nor tokenizer.batch_decode\n# after\nmodel.processor.tokenizer = model.processor.tokenizer_wrapper  # minimal shim\nresult = pipeline.convert(document)","handlingStrategy":"fallback","validationCode":"proc = model.processor\nhas_decode = callable(getattr(proc, 'batch_decode', None)) or getattr(proc, 'tokenizer', None) is not None\nif not has_decode:\n    raise RuntimeError('processor cannot decode; attach its tokenizer before conversion')","typeGuard":null,"tryCatchPattern":"try:\n    result = pipeline.convert(document)\nexcept RuntimeError as e:\n    if 'batch_decode' in str(e):\n        model.processor.tokenizer = model.processor.tokenizer_wrapper  # adapt to real attr name\n        result = pipeline.convert(document)\n    else:\n        raise","preventionTips":["Smoke-test one small document immediately after loading any unusual processor","Stick to repo_ids documented as supported by the Transformers engine","Report processors that hide the tokenizer so support can be added upstream"],"tags":["transformers","processor","decode","runtime-error"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}