conductor-oss/conductor · error · RuntimeException

{"error":{e.getMessage()},"response":{responseText}}

Error message

{"error":{e.getMessage()},"response":{responseText}}

What it means

Thrown by LLMHelper.tryToConvertToJSON() when the LLM response text cannot be parsed as JSON (JsonProcessingException) and isJsonOutput() is true. The exception carries a JSON string with the parse error message and the raw response text that failed to parse.

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/LLMHelper.java:317

                if (error != null) {
                    throw new RuntimeException(
                            String.format(
                                    "Output does not confirm to the schema.  errors: %s", error));
                }
            }
            // llmResponse.setResult(map);
            return map;

        } catch (JsonProcessingException e) {
            if (chatCompletion.isJsonOutput()) {
                log.error(
                        "error converting to json, response: {}, error: {}",
                        responseText,
                        e.getMessage(),
                        e);
                Map<String, Object> outputErrors =
                        Map.of("error", e.getMessage(), "response", responseText);
                throw new RuntimeException(objectMapper.writeValueAsString(outputErrors));
            }
            return responseText;
        }
    }

    private String validateJsonSchema(final SchemaDef schema, Map<String, Object> data) {
        try {
            // Order in which we use the schema
            // 1. If there is data -- inline schema def, we use that
            // 2. Else use name + version to lookup
            // 3. externalRef if present, in future we will use it -- currently not supported
            String schemaContent = objectMapper.writeValueAsString(schema.getData());
            if (schemaContent == null) {
                return null;
            }

            Set<ValidationMessage> validationMessages =
                    jsonSchemaValidator.validate(schemaContent, data);

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the 'response' field in the thrown JSON payload to see the raw text the model returned
  2. Increase maxTokens to prevent truncation of long JSON responses
  3. Strengthen the prompt with explicit instructions like 'Respond ONLY with valid JSON, no markdown, no explanation'
  4. Lower temperature to reduce non-deterministic formatting
  5. If using a provider that supports response_format json_object, enable it

Example fix

// before: prompt says 'Return a summary'
// after: prompt says 'Return ONLY valid JSON with no markdown fences, e.g. {"summary": "..."}'
Defensive patterns

Strategy: try-catch

Validate before calling

// Before the LLM call, ensure JSON output instructions are clear
if (chatCompletion.isJsonOutput()) {
    String prompt = chatCompletion.getPrompt();
    if (prompt != null && !prompt.toLowerCase().contains("json")) {
        log.warn("isJsonOutput is true but prompt does not mention JSON");
    }
}

Try / catch

try {
    LLMResponse response = llmHelper.chatComplete(task, llm, chatCompletion, location, logger);
} catch (RuntimeException e) {
    // Check if it's the JSON parse error with embedded payload
    if (e.getMessage().startsWith("{") && e.getMessage().contains("\"error\"")) {
        Map<String, Object> payload = objectMapper.readValue(e.getMessage(), Map.class);
        log.warn("LLM returned non-JSON when JSON expected: raw={}", payload.get("response"));
        // Optionally: re-prompt with stricter instructions or use a fallback parser
    }
    throw e;
}

Prevention

When it happens

Trigger: The LLM is asked for JSON output (isJsonOutput true) but returns text that is not valid JSON — e.g. natural language with embedded JSON fragments, markdown without code fences, or truncated JSON. objectMapper.readValue() throws JsonProcessingException.

Common situations: The model wrapped JSON in explanatory text (e.g. 'Here is the result: {...}'). The response was truncated due to maxTokens limit, cutting off the JSON mid-string. The model returned a code block with unexpected fence formatting. The model returned prose instead of JSON despite instructions.

Related errors


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