conductor-oss/conductor · error · IllegalStateException

PLAN_EXECUTE '${config.getName()}': tool '${t.getName()}' fa

Error message

PLAN_EXECUTE '${config.getName()}': tool '${t.getName()}' failed to serialise for PAC (${e.getMessage()}). The tool has ${guardrailCount} guardrail(s) — silently dropping it would compile a wrapper-less version of a safety-checked tool. Fix the ToolConfig (typically a non-Jackson-friendly value in inputSchema or config) and recompile.

What it means

Thrown as IllegalStateException when a PLAN_EXECUTE tool's ToolConfig cannot be serialized to a Map via Jackson's ObjectMapper.convertValue(). The compiler fail-closes on ALL serialization failures (not just guardrailed tools) because silently dropping a tool would leave PAC (Plan-Adaptive Compilation) without schema/guardrail context while knownToolNames still allowed it — a safety gap. The error message includes the tool name, the Jackson exception message, and the guardrail count.

Source

Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/compiler/MultiAgentCompiler.java:2639

            }
            try {
                @SuppressWarnings("unchecked")
                Map<String, Object> m = MAPPER.convertValue(t, Map.class);
                parentToolsAsMaps.add(m);
            } catch (Exception e) {
                // /dg #7: fail-closed on ALL serialization failures, not just
                // guardrailed ones. Previously a non-guardrailed tool was
                // silently dropped from parentToolsByName with only a WARN,
                // which meant ``knownToolNames`` still allowed the tool but
                // PAC had no schema / inputSchema / guardrail context — a
                // generate-op output landed in a bare SIMPLE with no
                // validation. Treat the divergence as a compile error so the
                // user fixes the ToolConfig (typically a non-Jackson-friendly
                // value in inputSchema or config) instead of shipping a
                // half-configured tool. Guardrailed tools get the longer
                // diagnostic since the failure mode there is more dangerous.
                int guardrailCount = t.getGuardrails() != null ? t.getGuardrails().size() : 0;
                throw new IllegalStateException(
                        "PLAN_EXECUTE '"
                                + config.getName()
                                + "': tool '"
                                + t.getName()
                                + "' failed to serialise for PAC ("
                                + e.getMessage()
                                + ")."
                                + (guardrailCount > 0
                                        ? " The tool has "
                                                + guardrailCount
                                                + " guardrail(s) — silently dropping it would compile a"
                                                + " wrapper-less version of a safety-checked tool."
                                        : " Silently dropping the tool would leave"
                                                + " ``knownToolNames`` allowing it while PAC has no schema or"
                                                + " inputSchema for validation.")
                                + " Fix the ToolConfig (typically a non-Jackson-friendly value"
                                + " in inputSchema or config) and recompile.",
                        e);

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the Jackson exception message embedded in the error — it names the field or type that failed serialization.
  2. Ensure all values in ToolConfig.config and inputSchema are JSON-serializable (Strings, Numbers, Booleans, Lists, Maps with String keys).
  3. Replace Pattern objects with regex strings, Class references with class name strings.
  4. Check for circular references in nested config objects.

Example fix

// before: non-serializable Pattern in inputSchema
ToolConfig.builder()
    .name("validate")
    .inputSchema(Map.of("pattern", Pattern.compile("^\\d+$")))  // Pattern is not Jackson-serializable
    .build();
// after: use the regex string
ToolConfig.builder()
    .name("validate")
    .inputSchema(Map.of("pattern", "^\\\\d+$"))
    .build();
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-serialize each tool to catch failures before compile
private static final ObjectMapper MAPPER = new ObjectMapper();

void preSerializeTools(List<ToolConfig> tools) {
    for (ToolConfig t : tools) {
        try {
            MAPPER.convertValue(t, Map.class);
        } catch (Exception e) {
            throw new IllegalStateException(
                "Tool '" + t.getName() + "' will fail PAC serialization: " + e.getMessage(), e);
        }
    }
}

Try / catch

try {
    compiler.compile(agentConfig);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("failed to serialise for PAC")) {
        // fix the non-Jackson-friendly value in the tool config
    }
    throw e;
}

Prevention

When it happens

Trigger: A PLAN_EXECUTE-strategy agent whose tool list contains a ToolConfig that Jackson cannot serialize to Map<String,Object>. Typically caused by a non-Jackson-friendly value in inputSchema or config — e.g., a raw Java class reference, a non-serializable object, a circular reference, or a custom type without a Jackson serializer.

Common situations: Putting non-JSON-serializable Java objects into ToolConfig.config or inputSchema (e.g., a Pattern object instead of a regex string, a Class<?> reference, or a deeply nested Map with non-String keys). Also happens when ToolConfig is constructed programmatically with values that can't round-trip through Jackson.

Related errors


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