{"record":{"id":"90f983d087ee34b9","repo":"oracle/graal","slug":"append-truncate-existing-not-allowed","errorCode":null,"errorMessage":"APPEND + TRUNCATE_EXISTING not allowed","messagePattern":"APPEND \\+ TRUNCATE_EXISTING not allowed","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java","lineNumber":155,"sourceCode":"            } else {\n                readable = true;\n            }\n        }\n\n        // set direct option\n        boolean direct = false;\n        for (OpenOption option : options) {\n            if (ExtendedOptions.DIRECT.matches(option)) {\n                direct = true;\n                break;\n            }\n        }\n        // check for Exceptions\n        if (readable && append) {\n            throw new IllegalArgumentException(\"READ + APPEND not allowed\");\n        }\n        if (append && options.contains(StandardOpenOption.TRUNCATE_EXISTING)) {\n            throw new IllegalArgumentException(\"APPEND + TRUNCATE_EXISTING not allowed\");\n        }\n\n        FileDescriptor fd = new FileDescriptor();\n        // populates fd via HostCode which opens the file and checks the permissions\n        newFileChannel0(TrufflePath.toTrufflePath(path), fd, openOptionsMask, fileAttributeMask);\n        return NewFileChannelHelper.open(fd, path.toString(), readable, writable, sync, direct, null);\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {\n        // ALL_PERMISSIONS is the default permission on Unix.\n        int fileAttributeMask = FileAttributeParser.parseWithDefault(FileAttributeParser.ALL_PERMISSIONS, attrs);\n        createDirectory0(TrufflePath.toTrufflePath(dir), fileAttributeMask);\n    }\n\n    @Override\n    public DirectoryStream<Path> newDirectoryStream(Path dir, DirectoryStream.Filter<? super Path> filter) throws IOException {","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/oracle/graal/blob/a66e9ccd1d7bf2552883939aa0788dfd0e294aab/espresso/src/com.oracle.truffle.espresso.io/src/sun/nio/fs/TruffleFileSystemProvider.java#L137-L173","documentation":"Thrown by TruffleFileSystemProvider.newFileChannel when the option set contains both APPEND and TRUNCATE_EXISTING. The two options are semantically contradictory: TRUNCATE_EXISTING erases the file on open while APPEND guarantees writes land at the current end. The provider rejects the pair before opening anything, matching JDK behavior.","triggerScenarios":"Files.newByteChannel(path, StandardOpenOption.APPEND, StandardOpenOption.TRUNCATE_EXISTING, ...) against a TrufflePath, typically because TRUNCATE_EXISTING was added unconditionally to a shared default option set.","commonSituations":"A generic 'openFile(mode)' helper that always adds TRUNCATE_EXISTING for write modes, then gets called with append=true; merging config-driven option lists without mutual-exclusion checks.","solutions":["Remove TRUNCATE_EXISTING wherever APPEND is requested","Model the two modes explicitly: write-fresh = CREATE + WRITE + TRUNCATE_EXISTING; append = CREATE + WRITE + APPEND","Assert the option set does not contain both flags before calling open"],"exampleFix":"// before\nSet<OpenOption> opts = new HashSet<>(Set.of(CREATE, WRITE, TRUNCATE_EXISTING));\nif (append) opts.add(APPEND);\nFileChannel ch = FileChannel.open(path, opts);\n\n// after\nSet<OpenOption> opts = new HashSet<>(Set.of(CREATE, WRITE));\nopts.add(append ? APPEND : TRUNCATE_EXISTING);\nFileChannel ch = FileChannel.open(path, opts);","handlingStrategy":"validation","validationCode":"boolean append = ...;\nSet<OpenOption> opts = new HashSet<>(Set.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE));\nopts.add(append ? StandardOpenOption.APPEND : StandardOpenOption.TRUNCATE_EXISTING);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make APPEND and TRUNCATE_EXISTING mutually exclusive branches in option-building code","Never union two caller-supplied option sets without checking this pair"],"tags":["espresso","nio","file-channel","open-options","truffle"],"backgroundTag":null,"analyzedSha":"a66e9ccd1d7bf2552883939aa0788dfd0e294aab","analyzedAt":"2026-08-14T13:58:47.161Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}