{"record":{"id":"ac5dae2629045378","repo":"alibaba/spring-ai-alibaba","slug":"workflow-config-invalid-ac5dae","errorCode":"WORKFLOW_CONFIG_INVALID","errorMessage":"${nodeName} vision param is not File or List<File>","messagePattern":"(.+?) vision param is not File or List<File>","errorType":"error_code","errorClass":"BizException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-core/src/main/java/com/alibaba/cloud/ai/studio/core/workflow/processor/impl/LLMExecuteProcessor.java","lineNumber":308,"sourceCode":"\t\t\t\telse if (value instanceof File) {\n\t\t\t\t\tMedia media = constructMedia(value);\n\t\t\t\t\tif (media == null) {\n\t\t\t\t\t\treturn new UserMessage(userPrompt);\n\t\t\t\t\t}\n\t\t\t\t\treturn UserMessage.builder().text(userPrompt).media(media).build();\n\t\t\t\t}\n\t\t\t\telse if (value instanceof List) {\n\t\t\t\t\tList<Media> mediaList = ((List<?>) value).stream()\n\t\t\t\t\t\t.map(this::constructMedia)\n\t\t\t\t\t\t.filter(Objects::nonNull)\n\t\t\t\t\t\t.collect(Collectors.toList());\n\t\t\t\t\tif (CollectionUtils.isEmpty(mediaList)) {\n\t\t\t\t\t\treturn new UserMessage(userPrompt);\n\t\t\t\t\t}\n\t\t\t\t\treturn UserMessage.builder().text(userPrompt).media(mediaList).build();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthrow new BizException(ErrorCode.WORKFLOW_CONFIG_INVALID\n\t\t\t\t\t\t.toError(node.getName() + \" vision param is not File or List<File>\"));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new UserMessage(userPrompt);\n\t}\n\n\t/**\n\t * Constructs a media object from the provided value\n\t * @param value The value to convert into media\n\t * @return A Media object if conversion is successful, null otherwise\n\t */\n\tprivate Media constructMedia(Object value) {\n\t\tif (value == null) {\n\t\t\treturn null;\n\t\t}\n\t\tif (!(value instanceof File)) {\n\t\t\tthrow new BizException(ErrorCode.WORKFLOW_CONFIG_INVALID.toError(\"object is not File\"));","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-core/src/main/java/com/alibaba/cloud/ai/studio/core/workflow/processor/impl/LLMExecuteProcessor.java#L290-L326","documentation":"LLMExecuteProcessor.constructUserMessage() builds a Spring AI UserMessage with media attachments when a vision parameter is configured. If the vision parameter value is neither a File nor a List<File> (so no media list could be built), it throws BizException WORKFLOW_CONFIG_INVALID naming the node.","triggerScenarios":"An LLM node's vision/image input variable resolves to a type other than File or List<File> — e.g. a plain String URL, Map, or JSON object — while constructing the user message in innerExecute.","commonSituations":"Upstream node outputs image URLs as strings instead of File objects; user wired a text variable into the vision input; file-reference format changed between framework versions.","solutions":["Ensure the value bound to the vision param is a File or List<File>; add a conversion node or use the file-reference variable type","If you have URLs, wrap them into the framework's File/media type expected by the LLM node","Check the upstream node's output type and select the correct output field in the vision parameter mapping"],"exampleFix":"// before (vision param bound to)\nString imageUrl = \"https://.../img.png\";\n// after\nList<File> images = List.of(new File(\"/tmp/img.png\")); // or file variable from upload node","handlingStrategy":"type-guard","validationCode":"Object vision = context.get(visionParam);\nif (!(vision instanceof File) && !(vision instanceof List<?>)) {\n    throw new IllegalStateException(node.getName() + \" vision param must be File or List<File>\");\n}","typeGuard":"static boolean isValidVisionParam(Object v) {\n    if (v instanceof File) return true;\n    if (v instanceof List<?> l) return l.isEmpty() || l.get(0) instanceof File;\n    return false;\n}","tryCatchPattern":"try {\n    processor.execute(graph, node, context);\n} catch (BizException e) {\n    if (ErrorCode.WORKFLOW_CONFIG_INVALID.getCode().equals(e.getCode()) && e.getMessage().endsWith(\"vision param is not File or List<File>\")) {\n        log.error(\"Fix vision input mapping on node: {}\", e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Bind only File or List<File> variables to vision inputs","Convert URL strings to the framework File/media type before the LLM node","Check upstream node output types when wiring multimodal workflows","Re-verify mappings after framework version upgrades that change file types"],"tags":["llm","vision","type-mismatch","workflow"],"backgroundTag":"type-mismatch","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"}