{"record":{"id":"c90416225102440f","repo":"docling-project/docling","slug":"missing-expected-kserve-v2-output-self-output-n","errorCode":null,"errorMessage":"Missing expected KServe v2 output: {self._output_name}","messagePattern":"Missing expected KServe v2 output: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"docling/models/inference_engines/image_classification/api_kserve_v2_engine.py","lineNumber":170,"sourceCode":"        # Type narrowing: _initialized guarantees these are non-None\n        assert self._processor is not None\n        assert self._kserve_client is not None\n        assert self._input_name is not None\n        assert self._output_name is not None\n\n        images = [item.image.convert(\"RGB\") for item in input_batch]\n        processed_inputs = self._processor(images=images, return_tensors=\"np\")\n        pixel_values = np.asarray(processed_inputs[\"pixel_values\"])\n\n        outputs = self._kserve_client.infer(\n            inputs={self._input_name: pixel_values},\n            output_names=[self._output_name],\n            request_parameters=self.options.request_parameters,\n        )\n        try:\n            logits_batch = outputs[self._output_name]\n        except KeyError as exc:\n            raise RuntimeError(\n                f\"Missing expected KServe v2 output: {self._output_name}\"\n            ) from exc\n\n        logits_batch = np.asarray(logits_batch, dtype=np.float32)\n        if logits_batch.ndim != 2:\n            raise RuntimeError(\n                \"Expected logits output shape [batch_size, num_classes], \"\n                f\"got shape={logits_batch.shape}\"\n            )\n\n        probs_batch = self._softmax(logits_batch)\n        return self._build_batch_outputs_from_probabilities(\n            input_batch=input_batch,\n            probs_batch=probs_batch,\n        )\n\n    def close(self) -> None:\n        if self._kserve_client is None:","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/docling-project/docling/blob/61d76f1ff3f8428065465889f7b4577da7df704c/docling/models/inference_engines/image_classification/api_kserve_v2_engine.py#L152-L188","documentation":"The inference response dictionary did not contain the output tensor name that the engine resolved from model metadata at initialization time. Docling requested output_names=[self._output_name] and then indexes the result by that key; a KeyError means the server returned results under different names than its metadata advertised.","triggerScenarios":"ApiKserveV2ImageClassificationEngine.predict_batch() when the server's InferResponse contents use an output name different from metadata.outputs[0].name (or omit it), so outputs[self._output_name] raises KeyError.","commonSituations":"Server restarted with a different model version between initialize() and predict(); custom server naming outputs inconsistently between metadata and inference responses; versionless endpoint being updated (canary rollout) behind the client's cached name.","solutions":["Re-create the engine (re-run initialize()) so tensor names are re-resolved against the current server state.","Pin options.model_version so metadata and inference hit the identical model revision.","Inspect the raw InferResponse output names server-side and align the server so inference responses match its advertised metadata names.","Avoid pointing the engine at auto-updating/canary endpoints; use a fixed version."],"exampleFix":"# before: versionless endpoint, model swapped mid-session\noptions.model_version = None\n\n# after: pin the version\noptions.model_version = \"v1\"","handlingStrategy":"retry","validationCode":"resp = kserve_client.infer(inputs=..., output_names=[name])\nif name not in resp:\n    available = list(resp.keys())\n    raise ValueError(f\"output '{name}' missing; server returned: {available}\")","typeGuard":null,"tryCatchPattern":"try:\n    engine.predict_batch(batch)\nexcept RuntimeError as e:\n    if \"Missing expected KServe v2 output\" in str(e):\n        engine.close()\n        engine = rebuild_engine()  # re-resolve tensor names\n        engine.initialize()\n        engine.predict_batch(batch)\n    else:\n        raise","preventionTips":["Pin options.model_version so the served model cannot change under you.","Log available output names when the mismatch occurs to speed diagnosis.","Recreate the engine when a server deployment event may have changed the model."],"tags":["kserve","output-name-mismatch","remote-inference","versioning"],"backgroundTag":null,"analyzedSha":"61d76f1ff3f8428065465889f7b4577da7df704c","analyzedAt":"2026-08-14T23:53:18.727Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}