{"record":{"id":"a73c0b5110cd553a","repo":"iflytek/astron-agent","slug":"8131-workflow-artifact-file-type-not-allowed","errorCode":"8131","errorMessage":"workflow.artifact.file.type.not.allowed","messagePattern":"workflow\\.artifact\\.file\\.type\\.not\\.allowed","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"warning","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowArtifactFileValidator.java","lineNumber":143,"sourceCode":"        this.properties = Objects.requireNonNull(properties);\n        this.ooxmlResourceLimits = Objects.requireNonNull(ooxmlResourceLimits);\n    }\n\n    public ValidatedArtifact validate(MultipartFile file) {\n        if (file == null || file.isEmpty() || StringUtils.isBlank(file.getOriginalFilename())) {\n            throw new BusinessException(ResponseEnum.PARAM_ERROR);\n        }\n        if (file.getSize() <= 0 || file.getSize() > properties.getArtifactMaxFileSize().toBytes()) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_ARTIFACT_FILE_TOO_LARGE);\n        }\n\n        String fileName = normalizeFileName(file.getOriginalFilename());\n        String extension = StringUtils.lowerCase(FilenameUtils.getExtension(fileName), Locale.ROOT);\n        Set<String> configuredExtensions = properties.getArtifactAllowedExtensions();\n        if (StringUtils.isBlank(extension)\n                || configuredExtensions.stream().noneMatch(extension::equalsIgnoreCase)\n                || !MEDIA_TYPES_BY_EXTENSION.containsKey(extension)) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_ARTIFACT_FILE_TYPE_NOT_ALLOWED);\n        }\n\n        String declaredType = normalizeMediaType(file.getContentType());\n        if (ACTIVE_CONTENT_TYPES.contains(declaredType)\n                || (!StringUtils.isBlank(declaredType)\n                        && !OCTET_STREAM.equals(declaredType)\n                        && !MEDIA_TYPES_BY_EXTENSION.get(extension).contains(declaredType))) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_ARTIFACT_CONTENT_TYPE_MISMATCH);\n        }\n\n        // Preflight Office containers before the general detector. OOXML resource limits run\n        // before its POI package parse inside validateOoxmlContainer.\n        validateOfficeContainer(file, extension);\n        String detectedType;\n        try (InputStream input = file.getInputStream()) {\n            detectedType = normalizeMediaType(tika.detect(input, fileName));\n        } catch (IOException exception) {\n            throw new BusinessException(ResponseEnum.WORKFLOW_ARTIFACT_CONTENT_TYPE_MISMATCH);","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowArtifactFileValidator.java#L125-L161","documentation":"WorkflowArtifactFileValidator.validate rejects artifact uploads whose filename extension is missing, is not in the configured allowed-extension list (SkillSandboxArtifactProperties.artifactAllowedExtensions), or has no registered media-type mapping in MEDIA_TYPES_BY_EXTENSION. The platform only accepts artifacts with a known, permitted extension (txt, md, csv, json, pdf, images, Office documents, zip). This is a policy error, not corruption: the file itself was never inspected.","triggerScenarios":"Calling validate() with a MultipartFile whose originalFilename has no extension (e.g. 'README'), whose extension is not present in properties.getArtifactAllowedExtensions(), or whose extension is allowed in config but absent from the validator's MEDIA_TYPES_BY_EXTENSION map (e.g. an extension added to config but unsupported in code).","commonSituations":"Users uploading files like .exe, .sh, .docm, or extensionless files; admins narrowing artifactAllowedExtensions so previously accepted types are now rejected; a new extension added to config without code support; clients sending filenames without extensions after path normalization strips them.","solutions":["Check the uploaded file's extension and rename/save it with a supported extension (txt, md, csv, json, pdf, png, jpg, jpeg, gif, webp, doc, xls, ppt, docx, xlsx, pptx, zip).","Verify the workflow artifact allowed-extensions configuration (SkillSandboxArtifactProperties.artifactAllowedExtensions) includes the extension you need; add it if missing.","If adding a genuinely new type, also add an entry to MEDIA_TYPES_BY_EXTENSION in WorkflowArtifactFileValidator — config alone is insufficient."],"exampleFix":"// before (config omits the type)\nartifact.allowed-extensions=txt,md,csv,json,pdf\n// after\nartifact.allowed-extensions=txt,md,csv,json,pdf,png,docx","handlingStrategy":"validation","validationCode":"String ext = StringUtils.lowerCase(FilenameUtils.getExtension(file.getOriginalFilename()));\nSet<String> allowed = properties.getArtifactAllowedExtensions();\nboolean ok = StringUtils.isNotBlank(ext) && allowed.stream().anyMatch(ext::equalsIgnoreCase);\nif (!ok) { /* reject before calling validate() */ }","typeGuard":null,"tryCatchPattern":"try { validator.validate(file); } catch (BusinessException e) { if (e.getResponse() == ResponseEnum.WORKFLOW_ARTIFACT_FILE_TYPE_NOT_ALLOWED) { /* return 4xx with allowed-extension hint to the client */ } throw e; }","preventionTips":["Validate the extension client-side against the documented allowed list before uploading.","Keep artifactAllowedExtensions and the validator's MEDIA_TYPES_BY_EXTENSION map in sync when adding types.","Strip client path components and send a clean filename with a real extension."],"tags":["file-upload","validation","content-policy","spring"],"backgroundTag":"unsupported-enum-value","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}