{"record":{"id":"aeb2a18ccc48f845","repo":"conductor-oss/conductor","slug":"unknown-termination-type-in-composite-type","errorCode":null,"errorMessage":"Unknown termination type in composite: ${type}","messagePattern":"Unknown termination type in composite: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/compiler/TerminationCompiler.java","lineNumber":318,"sourceCode":"\n    /**\n     * Build the inline JavaScript body for a single sub-condition within a composite. Each\n     * sub-condition evaluates to a local variable {@code rN} containing {@code {should_continue,\n     * reason}}.\n     */\n    private static String buildSubConditionBody(TerminationConfig sub, int index) {\n        String varName = \"r\" + index;\n        String type = sub.getType();\n\n        return switch (type) {\n            case \"text_mention\" -> buildInlineTextMention(sub, varName);\n            case \"stop_message\" -> buildInlineStopMessage(sub, varName);\n            case \"max_message\" -> buildInlineMaxMessage(sub, varName);\n            case \"token_usage\" -> buildInlineTokenUsage(sub, varName);\n            case \"and\" -> buildInlineComposite(sub, varName, true, index);\n            case \"or\" -> buildInlineComposite(sub, varName, false, index);\n            default ->\n                    throw new IllegalArgumentException(\n                            \"Unknown termination type in composite: \" + type);\n        };\n    }\n\n    private static String buildInlineTextMention(TerminationConfig config, String varName) {\n        String textJs = JavaScriptBuilder.toJson(config.getText());\n        boolean caseSensitive =\n                config.getCaseSensitive() != null ? config.getCaseSensitive() : true;\n\n        return \"  var \"\n                + varName\n                + \" = (function() {\"\n                + \"    var content = String($.result || '');\"\n                + \"    var text = \"\n                + textJs\n                + \";\"\n                + \"    var caseSensitive = \"\n                + caseSensitive","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/compiler/TerminationCompiler.java#L300-L336","documentation":"Thrown by buildSubConditionBody() when iterating sub-conditions inside a composite termination ('and'/'or') and encountering a sub-condition whose type is not one of the six supported values. This is the same validation as error 33 but applied to each entry in a composite's conditions list.","triggerScenarios":"A composite TerminationConfig (type='and' or 'or') whose conditions list contains at least one TerminationConfig with a null or unrecognized type string.","commonSituations":"One sub-condition in a composite has a typo in its type (e.g., 'token' instead of 'token_usage'), or a sub-condition was added with a null type. This is harder to spot because the error surfaces only when the composite is compiled, not when each sub-condition is defined.","solutions":["Inspect each sub-condition in the composite's conditions list and verify its type is one of: text_mention, stop_message, max_message, token_usage, and, or.","Check for null type values in sub-conditions.","Fix the specific sub-condition whose type is invalid."],"exampleFix":"// before: sub-condition has typo \"token\" instead of \"token_usage\"\nTerminationConfig.builder()\n    .type(\"or\")\n    .conditions(List.of(\n        TerminationConfig.builder().type(\"max_message\").maxMessages(10).build(),\n        TerminationConfig.builder().type(\"token\").maxTotalTokens(5000).build()))  // typo!\n    .build();\n// after\nTerminationConfig.builder()\n    .type(\"or\")\n    .conditions(List.of(\n        TerminationConfig.builder().type(\"max_message\").maxMessages(10).build(),\n        TerminationConfig.builder().type(\"token_usage\").maxTotalTokens(5000).build()))\n    .build();","handlingStrategy":"validation","validationCode":"private static final Set<String> VALID_TERM_TYPES =\n    Set.of(\"text_mention\", \"stop_message\", \"max_message\", \"token_usage\", \"and\", \"or\");\n\nvoid validateSubConditions(TerminationConfig composite) {\n    if (composite.getConditions() == null) return;\n    for (int i = 0; i < composite.getConditions().size(); i++) {\n        TerminationConfig sub = composite.getConditions().get(i);\n        if (sub.getType() == null || !VALID_TERM_TYPES.contains(sub.getType())) {\n            throw new IllegalArgumentException(\n                \"conditions[\" + i + \"] has unknown type: \" + sub.getType());\n        }\n    }\n}","typeGuard":"static boolean allSubConditionsValid(TerminationConfig composite) {\n    if (!Set.of(\"and\", \"or\").contains(composite.getType())) return true;\n    if (composite.getConditions() == null) return false;\n    return composite.getConditions().stream().allMatch(\n        c -> VALID_TERM_TYPES.contains(c.getType()));\n}","tryCatchPattern":"try {\n    String script = TerminationCompiler.buildTerminationScript(compositeConfig);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Unknown termination type in composite\")) {\n        // find and fix the sub-condition with the bad type\n    }\n    throw e;\n}","preventionTips":["Validate every sub-condition's type when building composites.","Use constants or enums for termination type strings.","Log sub-condition types during construction to catch null values early."],"tags":["termination","composite","config-validation","agentspan"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}