mlflow/mlflow · warning · NotImplementedError
LlamaIndex Workflow is not an engine
Error message
LlamaIndex Workflow is not an engine
What it means
Workflows are not query/chat engines, so WorkflowWrapper.engine_type raises NotImplementedError intentionally. Any code path that introspects .engine_type (e.g. routing logic, serialization metadata readers, or tools expecting a query/chat/retriever engine) hits this when the loaded model is a Workflow.
Source
Thrown at mlflow/llama_index/pyfunc_wrapper.py:179
def engine_type(self):
return RETRIEVER_ENGINE_NAME
def _predict_single(self, *args, **kwargs) -> list[dict[str, Any]]:
response = self._llama_model.retrieve(*args, **kwargs)
return [node.dict() for node in response]
def _format_predict_input(self, data) -> "QueryBundle":
return _format_predict_input_query_engine_and_retriever(data)
class WorkflowWrapper(_LlamaIndexModelWrapperBase):
@property
def index(self):
raise NotImplementedError("LlamaIndex Workflow does not have an index")
@property
def engine_type(self):
raise NotImplementedError("LlamaIndex Workflow is not an engine")
def predict(self, data, params: dict[str, Any] | None = None) -> list[str] | str:
inputs = self._format_predict_input(data, params)
# LlamaIndex Workflow runs async but MLflow pyfunc doesn't support async inference yet.
predictions = self._wait_async_task(self._run_predictions(inputs))
# Even if the input is single instance, the signature enforcement convert it to a Pandas
# DataFrame with a single row. In this case, we should unwrap the result (list) so it
# won't be inconsistent with the output without signature enforcement.
should_unwrap = len(data) == 1 and isinstance(predictions, list)
return predictions[0] if should_unwrap else predictions
def _format_predict_input(
self, data, params: dict[str, Any] | None = None
) -> list[dict[str, Any]]:
inputs = _convert_llm_input_data_with_unwrapping(data)
params = params or {}View on GitHub (pinned to 6a27f2decc)
Solutions
- Guard with try/except NotImplementedError or check the underlying type (Workflow) before reading engine_type.
- If downstream code requires an engine_type, save an index/engine-based model instead of a Workflow.
- Treat Workflow models as predict()-only and adjust dispatch logic to a no-op/"workflow" branch.
Example fix
// before
print(f"engine: {model.engine_type}")
// after
try:
print(f"engine: {model.engine_type}")
except NotImplementedError:
print("engine: workflow (no engine)") Defensive patterns
Strategy: type-guard
Validate before calling
from llama_index.core.workflow import Workflow
def safe_engine_type(model):
if isinstance(getattr(model, "_llama_model", None), Workflow):
return "workflow"
return model.engine_type Type guard
def has_engine_type(model) -> bool:
from llama_index.core.workflow import Workflow
return not isinstance(getattr(model, "_llama_model", None), Workflow) Try / catch
try:
etype = model.engine_type
except NotImplementedError:
etype = "workflow" Prevention
- Guard engine_type reads behind a helper with a 'workflow' default.
- Don't dispatch strictly on engine_type; handle the Workflow case.
- Keep metadata collectors tolerant of NotImplementedError.
- Prefer explicit model-type checks over property probing.
When it happens
Trigger: Reading model.engine_type on a pyfunc loaded from a model saved as a LlamaIndex Workflow; MLflow-adjacent utilities or logging code that unconditionally reads engine_type.
Common situations: Generic model-metadata collectors; pipelines that dispatch on engine_type after swapping an engine-based model for a Workflow; test harnesses asserting engine_type for all LlamaIndex models.
Related errors
- LlamaIndex Workflow does not have an index
- Unsupported input type: {type(x)}. It must be a dictionary.
- NotImplementedError
- NotImplementedError
- This method is not implemented for `MlflowDeploymentClient`.
AI-assisted analysis of mlflow/mlflow@6a27f2decc (2026-08-29).
Data as JSON: /api/errors/8ba62655ca952a58.
Report an issue: GitHub.