{"record":{"id":"907f98b6de68b43b","repo":"quarkusio/quarkus","slug":"invalid-workspace-path-uristring","errorCode":null,"errorMessage":"Invalid workspace path: ${uriString}","messagePattern":"Invalid workspace path: (.+?)","errorType":"exception","errorClass":"SecurityException","httpStatus":null,"severity":"error","filePath":"extensions/devui/deployment/src/main/java/io/quarkus/devui/deployment/menu/WorkspaceProcessor.java","lineNumber":363,"sourceCode":"\n    /**\n     * Resolve a client supplied path URI and make sure it stays confined to the project root.\n     * The workspace operations are only meant to act on files inside the user's project, so any\n     * path (including ones using {@code ..} or symlinks) that resolves outside the root is rejected.\n     */\n    private static Path resolveWorkspacePath(Path rootPath, String uriString) {\n        if (uriString == null) {\n            throw new SecurityException(\"No workspace path provided\");\n        }\n\n        Path root;\n        Path resolved;\n        try {\n            root = toCanonicalPath(rootPath);\n            resolved = toCanonicalPath(Paths.get(URI.create(uriString)));\n        } catch (IllegalArgumentException | FileSystemNotFoundException | IOException e) {\n            // Malformed URI, a non-file scheme or a path we cannot safely canonicalize: reject it.\n            throw new SecurityException(\"Invalid workspace path: \" + uriString);\n        }\n\n        if (!resolved.startsWith(root)) {\n            throw new SecurityException(\"Path is outside the project root: \" + resolved);\n        }\n        return resolved;\n    }\n\n    /**\n     * Normalize a path to an absolute form with symlinks resolved. The file itself may not exist\n     * yet (e.g. when creating a new workspace item), so symlinks are only resolved on the nearest\n     * existing ancestor to prevent a symlinked directory from escaping the root. If the real path\n     * cannot be determined the {@link IOException} is propagated so the caller can fail closed\n     * rather than fall back to an unresolved (potentially escaping) path.\n     */\n    private static Path toCanonicalPath(Path path) throws IOException {\n        Path absolute = path.toAbsolutePath().normalize();\n        Path existing = absolute;","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/devui/deployment/src/main/java/io/quarkus/devui/deployment/menu/WorkspaceProcessor.java#L345-L381","documentation":"Dev UI workspace actions confine file operations to the project root. resolveWorkspacePath parses the client URI and canonicalizes both root and target; if URI creation fails (malformed URI, non-file scheme such as http:, or a path that cannot be safely canonicalized due to I/O errors), it throws SecurityException with 'Invalid workspace path'. This rejects unsafe or unparseable inputs before any file access.","triggerScenarios":"Calling a workspace action with uriString that is not a valid URI (illegal characters, spaces), uses a non-file scheme (http://, jar:), or whose Path canonicalization (toCanonicalPath) throws IllegalArgumentException, FileSystemNotFoundException, or IOException.","commonSituations":"Passing a raw filesystem path ('/home/user/file.java') instead of a file: URI; URL-unsafe characters not percent-encoded; pointing at a non-file filesystem; network filesystem issues causing I/O failures during canonicalization.","solutions":["Send a properly formed file URI: Paths.get(...).toUri().toString() on the client side.","Percent-encode spaces and special characters in the URI.","Use only file-scheme URIs on local filesystems the dev-mode process can access.","Ensure the path's filesystem is available (mounted) before invoking the action."],"exampleFix":"// before\nString uri = \"/home/user/project/src/App.java\"; // not a URI\n\n// after\nString uri = java.nio.file.Paths.get(\"/home/user/project/src/App.java\").toUri().toString();","handlingStrategy":"try-catch","validationCode":"URI uri;\ntry { uri = new URI(candidate); } catch (URISyntaxException e) {\n    throw new IllegalArgumentException(\"Not a valid URI: \" + candidate, e);\n}\nif (!\"file\".equals(uri.getScheme())) throw new IllegalArgumentException(\"Only file: URIs are supported\");","typeGuard":null,"tryCatchPattern":"try { Path p = resolveWorkspacePath(root, uriString); ... }\ncatch (SecurityException e) {\n    if (e.getMessage().startsWith(\"Invalid workspace path\")) {\n        ui.showError(\"Send a canonical file: URI, e.g. Paths.get(path).toUri()\");\n    } else throw e;\n}","preventionTips":["Build URIs with Paths.get(...).toUri() instead of string concatenation","Percent-encode spaces and special characters","Only use file-scheme URIs on accessible local filesystems"],"tags":["devui","workspace","security","uri-parsing"],"backgroundTag":"invalid-path-uri","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}