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

  1. Read the two log.error lines emitted before the throw: the first dumps the full inputData, the second the root exception + stack trace.
  2. Validate the chat-complete task input schema (model, messages/userInput, llmProvider) against ChatCompletion.
  3. Ensure every ${...} placeholder in messages has a matching key in promptVariables.
  4. Confirm referenced participant/tool taskRefNames exist earlier in the workflow.
  5. 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

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


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/9a6039b08296ed6b. Report an issue: GitHub.