{"record":{"id":"b86d95973798c342","repo":"alibaba/spring-ai-alibaba","slug":"invalid-dify-dsl","errorCode":null,"errorMessage":"invalid dify dsl","messagePattern":"invalid dify dsl","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/dsl/adapters/DifyDSLAdapter.java","lineNumber":75,"sourceCode":"/**\n * DifyDSLAdapter converts Dify DSL to {@link App} and vice versa.\n */\n@Component\npublic class DifyDSLAdapter extends AbstractDSLAdapter {\n\n\tprivate static final String[] DIFY_CHATBOT_MODES = { \"chat\", \"completion\", \"agent-chat\" };\n\n\tprivate static final String[] DIFY_WORKFLOW_MODES = { \"workflow\", \"advanced-chat\" };\n\n\tpublic DifyDSLAdapter(List<NodeDataConverter<? extends NodeData>> nodeDataConverters,\n\t\t\t@Qualifier(\"yaml\") Serializer serializer) {\n\t\tsuper(nodeDataConverters, serializer);\n\t}\n\n\t@Override\n\tpublic void validateDSLData(Map<String, Object> dslData) {\n\t\tif (dslData == null || !dslData.containsKey(\"app\")) {\n\t\t\tthrow new IllegalArgumentException(\"invalid dify dsl\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic Serializer getSerializer() {\n\t\treturn serializer;\n\t}\n\n\t@Override\n\tpublic AppMetadata mapToMetadata(Map<String, Object> data) {\n\t\tMap<String, Object> map = (Map<String, Object>) data.get(\"app\");\n\t\tAppMetadata metadata = new AppMetadata();\n\t\tif (Arrays.asList(DIFY_CHATBOT_MODES).contains((String) map.get(\"mode\"))) {\n\t\t\tmetadata.setMode(AppMetadata.CHATBOT_MODE);\n\t\t}\n\t\telse if (Arrays.asList(DIFY_WORKFLOW_MODES).contains((String) map.get(\"mode\"))) {\n\t\t\tmetadata.setMode(AppMetadata.WORKFLOW_MODE);\n\t\t}","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-start/src/main/java/com/alibaba/cloud/ai/studio/admin/builder/generator/service/dsl/adapters/DifyDSLAdapter.java#L57-L93","documentation":"Thrown by DifyDSLAdapter.validateDSLData when the provided DSL data is null or does not contain a top-level 'app' key. Dify exports always carry an 'app' object holding mode, name, and description, so its absence means the document is not a valid Dify DSL. This is the first gate before mode mapping and conversion.","triggerScenarios":"Calling importDSL/validateDSLData with a null map; passing a DSL missing the 'app' key; passing a Spring AI Alibaba native or Studio DSL to the Dify adapter; passing only the inner app object rather than the wrapper containing it.","commonSituations":"Uploading the wrong file type (native DSL instead of a Dify YAML/JSON export); extracting the inner app object and passing it instead of the full document; YAML parsing that flattened the structure; automated pipelines mixing adapter inputs.","solutions":["Pass the full Dify export document including its top-level 'app' object","Verify you selected the DifyDSLAdapter for a Dify export (use Studio/Agent adapters for their own formats)","Check YAML/JSON parsing did not drop or rename the 'app' key","Log the parsed map keys before import to confirm structure"],"exampleFix":"// before\nMap.of(\"mode\", \"chat\", \"name\", \"bot\")\n\n// after\nMap.of(\"app\", Map.of(\"mode\", \"chat\", \"name\", \"bot\"))","handlingStrategy":"validation","validationCode":"if (dslData == null || !dslData.containsKey(\"app\")) {\n    throw new IllegalArgumentException(\"not a valid Dify DSL: top-level 'app' object required\");\n}","typeGuard":"boolean isDifyDsl(Map<String,Object> dsl) { return dsl != null && dsl.get(\"app\") instanceof Map; }","tryCatchPattern":"try { difyAdapter.importDSL(dslData); } catch (IllegalArgumentException e) { log.error(\"Dify DSL missing 'app': check file format\"); throw e; }","preventionTips":["Import the complete Dify export document, not the inner app object","Confirm the file is a Dify export before choosing the Dify adapter","Check YAML/JSON parsing preserved the top-level 'app' key"],"tags":["dsl","dify","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}