{"record":{"id":"b661ce90a9ccbc3c","repo":"libgdx/libgdx","slug":"cannot-write-to-files-in-gwt-backend","errorCode":null,"errorMessage":"Cannot write to files in GWT backend","messagePattern":"Cannot write to files in GWT backend","errorType":"exception","errorClass":"GdxRuntimeException","httpStatus":null,"severity":"error","filePath":"backends/gdx-backends-gwt/src/com/badlogic/gdx/backends/gwt/GwtFileHandle.java","lineNumber":231,"sourceCode":"\t\t\t}\n\t\t}\n\t\treturn position - offset;\n\t}\n\n\tpublic ByteBuffer map () {\n\t\tthrow new GdxRuntimeException(\"Cannot map files in GWT backend\");\n\t}\n\n\tpublic ByteBuffer map (FileChannel.MapMode mode) {\n\t\tthrow new GdxRuntimeException(\"Cannot map files in GWT backend\");\n\t}\n\n\t/** Returns a stream for writing to this file. Parent directories will be created if necessary.\n\t * @param append If false, this file will be overwritten if it exists, otherwise it will be appended.\n\t * @throws GdxRuntimeException if this file handle represents a directory, if it is a {@link FileType#Classpath} or\n\t *            {@link FileType#Internal} file, or if it could not be written. */\n\tpublic OutputStream write (boolean append) {\n\t\tthrow new GdxRuntimeException(\"Cannot write to files in GWT backend\");\n\t}\n\n\t/** Reads the remaining bytes from the specified stream and writes them to this file. The stream is closed. Parent directories\n\t * will be created if necessary.\n\t * @param append If false, this file will be overwritten if it exists, otherwise it will be appended.\n\t * @throws GdxRuntimeException if this file handle represents a directory, if it is a {@link FileType#Classpath} or\n\t *            {@link FileType#Internal} file, or if it could not be written. */\n\tpublic void write (InputStream input, boolean append) {\n\t\tthrow new GdxRuntimeException(\"Cannot write to files in GWT backend\");\n\t}\n\n\t/** Returns a writer for writing to this file using the default charset. Parent directories will be created if necessary.\n\t * @param append If false, this file will be overwritten if it exists, otherwise it will be appended.\n\t * @throws GdxRuntimeException if this file handle represents a directory, if it is a {@link FileType#Classpath} or\n\t *            {@link FileType#Internal} file, or if it could not be written. */\n\tpublic Writer writer (boolean append) {\n\t\treturn writer(append, null);\n\t}","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/libgdx/libgdx/blob/97f40861878058087be0685ca167ddfde132134b/backends/gdx-backends-gwt/src/com/badlogic/gdx/backends/gwt/GwtFileHandle.java#L213-L249","documentation":"GwtFileHandle.write(boolean append) always throws: the GWT backend is strictly read-only for files because assets live in the preloaded, in-memory bundle and browsers give JavaScript no arbitrary file-write capability. Every write-family method in this class (write, write(InputStream,...), writer, writeString, writeBytes) is overridden to throw the same message.","triggerScenarios":"Calling write(append) on a FileHandle in the GWT backend — directly, or via shared code such as Preferences serializers, level editors, screenshot savers, or libraries that persist data with Gdx.files.local(...).write(...).","commonSituations":"Porting a desktop game that saves state with FileHandle.write; JSON/XML libraries that serialize to a FileHandle; screenshot or replay features that dump files; code assuming LocalStorage-like file semantics exist.","solutions":["Persist web-build state with Preferences (Gdx.app.getPreferences) or HTML5 local storage instead of FileHandle writes.","Branch on Gdx.app.getType() == ApplicationType.WebGL and route all persistence through a platform-specific interface (web: Preferences/localStorage; desktop: files).","For downloads (screenshots, exported saves), use browser APIs (e.g. a GWT-native anchor download) rather than the filesystem.","Audit shared code for write()/writer()/writeString()/writeBytes()/copyTo/moveTo calls before adding the GWT target."],"exampleFix":"// before\nGdx.files.local(\"save.json\").writeString(json, false); // throws on GWT\n\n// after\nif (Gdx.app.getType() == ApplicationType.WebGL) {\n    Gdx.app.getPreferences(\"save\").putString(\"json\", json).flush();\n} else {\n    Gdx.files.local(\"save.json\").writeString(json, false);\n}","handlingStrategy":"validation","validationCode":"// all writes must be routed away from FileHandle on GWT\nif (Gdx.app.getType() == ApplicationType.WebGL) {\n    Gdx.app.getPreferences(\"data\").putString(\"key\", value).flush();\n} else {\n    fh.writeString(value, false);\n}","typeGuard":"static boolean isFilesystemWritable () {\n    return Gdx.app.getType() != ApplicationType.WebGL;\n}","tryCatchPattern":null,"preventionTips":["Introduce a Persistence interface at project start so the web implementation never touches FileHandle writes.","Audit shared modules for write(/writer(/writeString(/writeBytes( calls before adding the GWT target.","Use Gdx.app.log for logs instead of file-based logging in shared code."],"tags":["gwt","libgdx","filehandle","write","read-only","unsupported-operation"],"backgroundTag":null,"analyzedSha":"97f40861878058087be0685ca167ddfde132134b","analyzedAt":"2026-08-14T10:52:53.492Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}