conductor-oss/conductor · critical · TerminateWorkflowException
Error preparing chat completion task input: %s
Error message
Error preparing chat completion task input: %s
What it means
Thrown by ChatCompleteTaskMapper.getMappedTask as a TerminateWorkflowException when any exception occurs while preparing a chat completion task's input (JSON conversion of inputData to ChatCompletion, history collection, or template substitution). It re-throws pre-existing TerminateWorkflowExceptions unchanged but wraps all other exceptions, logging the raw inputData and stack trace first. This terminates the entire workflow, not just the task.
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/tasks/mapper/ChatCompleteTaskMapper.java:104
history.add(new ChatMessage(ChatMessage.Role.user, chatCompletion.getUserInput()));
}
// getHistory() internally skips prior loop-iteration assistant messages
// for this same task refName when (a) previousResponseId is in play
// (OpenAI Responses API server-side store owns the prior turns) or
// (b) the provider declares it doesn't accept assistant-message
// prefill (AIModel.supportsAssistantPrefill — e.g. Anthropic, where
// Claude Sonnet 4.6+ rejects prefill outright). Participants, tool
// calls, and sub-workflow context are still preserved in both cases.
getHistory(workflowModel, taskModel, chatCompletion);
updateTaskModel(chatCompletion, taskModel);
} catch (Exception e) {
if (e instanceof TerminateWorkflowException) {
throw (TerminateWorkflowException) e;
} else {
log.error("input: {}", taskModel.getInputData());
log.error(e.getMessage(), e);
throw new TerminateWorkflowException(
String.format(
"Error preparing chat completion task input: %s", e.getMessage()));
}
}
return taskModel;
}
protected void updateTaskModel(ChatCompletion chatCompletion, TaskModel simpleTask) {
Map<String, Object> paramReplacement = chatCompletion.getPromptVariables();
if (paramReplacement == null) {
paramReplacement = new HashMap<>();
}
List<ChatMessage> messages = chatCompletion.getMessages();
if (messages == null) {
messages = new ArrayList<>();
}
for (ChatMessage message : messages) {
String msgText = message.getMessage();View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Read the two log.error lines emitted before the throw: the first dumps the full inputData, the second the root exception + stack trace.
- Validate the chat-complete task input schema (model, messages/userInput, llmProvider) against ChatCompletion.
- Ensure every ${...} placeholder in messages has a matching key in promptVariables.
- Confirm referenced participant/tool taskRefNames exist earlier in the workflow.
- Wrap risky upstream tasks so their output is always mappable to LLMResponse.
Example fix
// before (workflow input missing required fields)
{
"llmProvider": "openai",
"model": "gpt-4o"
// missing messages / userInput -> Jackson/NullPointerException
}
// after
{
"llmProvider": "openai",
"model": "gpt-4o",
"userInput": "Summarize the report",
"promptVariables": {"topic": "sales"}
} Defensive patterns
Strategy: validation
Validate before calling
Object input = taskModel.getInputData();
if (input == null || (!(input instanceof Map) && !(input instanceof ChatCompletion))) {
throw new IllegalArgumentException("chat-complete task input is missing or wrong type");
}
// Ensure at least one prompt source is present
Map<?,?> map = (Map<?,?>) input;
if (!map.containsKey("messages") && !map.containsKey("userInput")) {
throw new IllegalArgumentException("chat-complete task requires 'messages' or 'userInput'");
} Try / catch
// TerminateWorkflowException is not catchable in user code (engine-level);
// prevent it by validating input before the mapper runs.
// In a worker, surface mapping failures via task output instead.
try {
objectMapper.convertValue(inputData, ChatCompletion.class);
} catch (IllegalArgumentException e) {
// fix the input shape before the task is scheduled Prevention
- Validate chat-complete task input schema before running the workflow.
- Provide a promptVariables entry for every ${...} placeholder used in messages.
- Ensure referenced participant/tool taskRefNames exist earlier in the workflow.
- Read the two log.error lines emitted by the mapper to find the root cause.
- Make upstream task outputs always mappable to LLMResponse (include a 'result' field).
When it happens
Trigger: taskModel.getInputData() cannot be converted to ChatCompletion (Jackson mismatch/missing required field), an NPE during getHistory (e.g. a task with null WorkflowTask or missing taskReferenceName), or a StringTemplate.fString failure on a ${...} variable with no replacement value.
Common situations: A workflow author provides chat-complete task input with the wrong shape (missing 'messages'/'userInput'), references a participant/tool taskRefName that does not exist, uses a ${variable} with no promptVariables mapping, or a prior task output that cannot be coerced into LLMResponse.
Related errors
- PLAN_EXECUTE '${config.getName()}': tool '${t.getName()}' fa
- Skill manifest name '{manifestName}' does not match package
- Skill {name} version {version} already exists with a differe
- File path is required
- Skill file is too large to preview: {cleanPath}
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/9a6039b08296ed6b.
Report an issue: GitHub.