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
- Inspect the Jackson exception message embedded in the error — it names the field or type that failed serialization.
- Ensure all values in ToolConfig.config and inputSchema are JSON-serializable (Strings, Numbers, Booleans, Lists, Maps with String keys).
- Replace Pattern objects with regex strings, Class references with class name strings.
- 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
- Never put non-JSON types (Pattern, Class, File, etc.) in ToolConfig fields.
- Pre-serialize tool configs with ObjectMapper.convertValue() in a test to catch issues early.
- All Map keys must be Strings; all values must be primitives, Strings, Lists, or nested Maps.
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
- PLAN_EXECUTE strategy requires ``planner=<Agent>`` on the pa
- PLAN_EXECUTE harness '${config.getName()}' has guardrails wi
- ${usx.message}
- plan_source must include a non-empty 'tool' field
- plan_source.tool '${toolName}' is not registered as a harnes
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/e42aeba35314b242.
Report an issue: GitHub.