{"record":{"id":"029df4405e6e9069","repo":"jenkinsci/jenkins","slug":"invalid-mode","errorCode":null,"errorMessage":"Invalid mode: {}","messagePattern":"Invalid mode: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/hudson/Util.java","lineNumber":1779,"sourceCode":"    public static int permissionsToMode(Set<PosixFilePermission> permissions) {\n        PosixFilePermission[] allPermissions = PosixFilePermission.values();\n        int result = 0;\n        for (PosixFilePermission allPermission : allPermissions) {\n            result <<= 1;\n            result |= permissions.contains(allPermission) ? 1 : 0;\n        }\n        return result;\n    }\n\n    @Restricted(NoExternalUse.class)\n    public static Set<PosixFilePermission> modeToPermissions(int mode) throws IOException {\n         // Anything larger is a file type, not a permission.\n        int PERMISSIONS_MASK = 07777;\n        // setgid/setuid/sticky are not supported.\n        int MAX_SUPPORTED_MODE = 0777;\n        mode = mode & PERMISSIONS_MASK;\n        if ((mode & MAX_SUPPORTED_MODE) != mode) {\n            throw new IOException(\"Invalid mode: \" + mode);\n        }\n        PosixFilePermission[] allPermissions = PosixFilePermission.values();\n        Set<PosixFilePermission> result = EnumSet.noneOf(PosixFilePermission.class);\n        for (int i = 0; i < allPermissions.length; i++) {\n            if ((mode & 1) == 1) {\n                result.add(allPermissions[allPermissions.length - i - 1]);\n            }\n            mode >>= 1;\n        }\n        return result;\n    }\n\n    /**\n     * Converts a {@link File} into a {@link Path} and checks runtime exceptions.\n     * @throws IOException if {@code f.toPath()} throws {@link InvalidPathException}.\n     */\n    @Restricted(NoExternalUse.class)\n    public static @NonNull Path fileToPath(@NonNull File file) throws IOException {","sourceCodeStart":1761,"sourceCodeEnd":1797,"githubUrl":"https://github.com/jenkinsci/jenkins/blob/2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc/core/src/main/java/hudson/Util.java#L1761-L1797","documentation":"Thrown by Util.modeToPermissions(int mode) when the mode value, after masking with 07777 (stripping file-type bits), still contains bits in the 07000 range — i.e., setuid (04000), setgid (02000), or sticky (01000). The check is (mode & 0777) != mode after masking; if any bit above 0777 remains, the mode is rejected because these special permission bits are not supported by the POSIX file permission mapping.","triggerScenarios":"modeToPermissions is called with a mode like 02755 (setgid), 04755 (setuid), 01775 (sticky), or 07777 (all bits) — after masking with PERMISSIONS_MASK (07777), the result still has bits above MAX_SUPPORTED_MODE (0777), so the guard fails.","commonSituations":"Passing a raw Unix octal mode from a configuration field that allows setgid/setuid/sticky bits; copying a chmod value from system documentation that includes special bits; a plugin or configuration UI that accepts full numeric modes without filtering special bits.","solutions":["Mask the mode value to 0777 before passing it: use mode & 0777 to strip setuid/setgid/sticky bits.","If special bits are genuinely needed, handle them separately with native filesystem calls (e.g., chmod via ProcessBuilder) since Jenkins' POSIX permission API does not support them.","Update the configuration input to only accept 3-digit octal values (000-777)."],"exampleFix":"// before\nSet<PosixFilePermission> perms = Util.modeToPermissions(02755);\n\n// after\nSet<PosixFilePermission> perms = Util.modeToPermissions(02755 & 0777); // strips setgid","handlingStrategy":"validation","validationCode":"// Strip special bits before calling modeToPermissions\nint safeMode = mode & 0777; // removes setuid/setgid/sticky\nSet<PosixFilePermission> perms = Util.modeToPermissions(safeMode);","typeGuard":null,"tryCatchPattern":"try {\n    Set<PosixFilePermission> perms = Util.modeToPermissions(mode);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Invalid mode:\")) {\n        // Retry with stripped special bits\n        perms = Util.modeToPermissions(mode & 0777);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always mask mode values to 0777 before passing to modeToPermissions.","Validate user-supplied chmod values in configuration forms to reject special bits.","Document that setuid/setgid/sticky are unsupported in Jenkins permission APIs."],"tags":["filesystem","permissions","validation","posix"],"backgroundTag":null,"analyzedSha":"2e228ff40b14dbc8b14ffbc6edf0e4383cf744fc","analyzedAt":"2026-08-14T07:07:15.274Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}