{"record":{"id":"255624b165ee5c6f","repo":"OtterMind/Chat2DB","slug":"unsupported-sql-directory-child-type","errorCode":null,"errorMessage":"Unsupported SQL directory child type","messagePattern":"Unsupported SQL directory child type","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"chat2db-community-server/chat2db-community-jcef/src/main/java/ai/chat2db/community/jcef/handler/biz/SqlDirectoryTreeStore.java","lineNumber":119,"sourceCode":"            overflowNode.put(\"loaded\", true);\n            children.add(overflowNode);\n        }\n\n        return children;\n    }\n\n    static Map<String, Object> createChild(String rootToken, String parentRelativePath, String rawName, String type)\n            throws IOException {\n        Path root = getRoot(rootToken);\n        Path parent = resolveInRoot(root, parentRelativePath);\n        if (!Files.isDirectory(parent, LinkOption.NOFOLLOW_LINKS)) {\n            throw new IllegalArgumentException(\"Selected path is not a directory\");\n        }\n\n        boolean directory = \"directory\".equals(type);\n        boolean file = \"file\".equals(type);\n        if (!directory && !file) {\n            throw new IllegalArgumentException(\"Unsupported SQL directory child type\");\n        }\n\n        String name = file ? normalizeFileName(rawName, \"sql\") : normalizeDirectoryName(rawName);\n        Path target = parent.resolve(name).normalize();\n        if (!target.startsWith(root)) {\n            throw new IllegalArgumentException(\"Path is outside of the selected SQL directory\");\n        }\n        if (Files.exists(target, LinkOption.NOFOLLOW_LINKS)) {\n            throw new IllegalArgumentException(\"File or directory already exists\");\n        }\n\n        if (directory) {\n            Files.createDirectory(target);\n        } else {\n            Files.createFile(target);\n        }\n\n        Path realTarget = target.toRealPath(LinkOption.NOFOLLOW_LINKS);","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-jcef/src/main/java/ai/chat2db/community/jcef/handler/biz/SqlDirectoryTreeStore.java#L101-L137","documentation":"Thrown by SqlDirectoryTreeStore.createChild() when the 'type' parameter is neither 'directory' nor 'file'. The method checks exact string equality against these two values and rejects anything else. This is a contract violation between the frontend and the JCEF bridge — the type enum is not extensible.","triggerScenarios":"Invoked via create-sql-directory-child JCEF action when the JSON 'type' field is null, empty, or an unrecognized string (e.g., 'folder', 'dir', 'document', 'symlink').","commonSituations":"Frontend uses a different label for the type (e.g., 'folder' instead of 'directory'); the type field is omitted from the request; a new file type was added to the frontend without updating the backend contract.","solutions":["Ensure the frontend sends exactly 'directory' or 'file' as the type value","Add frontend validation that maps UI labels to the exact backend enum before sending the request","Document the accepted type values in the API contract shared between frontend and backend"],"exampleFix":"// before: frontend sends arbitrary type label\ncreateChild(rootToken, parentPath, name, uiLabel); // uiLabel = 'folder'\n\n// after: normalize to backend contract\nconst typeMap = { folder: 'directory', dir: 'directory', file: 'file' };\ncreateChild(rootToken, parentPath, name, typeMap[uiLabel] ?? uiLabel);","handlingStrategy":"type-guard","validationCode":"// Validate type before calling createChild\nprivate static final Set<String> VALID_TYPES = Set.of(\"directory\", \"file\");\nif (!VALID_TYPES.contains(type)) {\n    throw new IllegalArgumentException(\"Type must be 'directory' or 'file', got: \" + type);\n}\nSqlDirectoryTreeStore.createChild(rootToken, parentRelativePath, name, type);","typeGuard":"// Type guard for the child type enum\nstatic boolean isValidChildType(String type) {\n    return \"directory\".equals(type) || \"file\".equals(type);\n}","tryCatchPattern":"try {\n    Map<String, Object> result = SqlDirectoryTreeStore.createChild(rootToken, parentRelativePath, name, type);\n    ResponseBuilder.buildSuccessJcef(Map.of(\"data\", result), callback);\n} catch (IllegalArgumentException e) {\n    callback.failure(400, e.getMessage());\n}","preventionTips":["Map frontend UI labels to the exact backend enum ('directory', 'file') before sending","Share the type enum as a TypeScript union type in the frontend contract","Default the type to 'file' if the frontend does not explicitly set it"],"tags":["sql-directory","contract-validation","user-input","frontend"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}