{"record":{"id":"6c0d69fb582b0366","repo":"MuntashirAkon/AppManager","slug":"backup-is-in-read-only-mode","errorCode":null,"errorMessage":"Backup is in read-only mode.","messagePattern":"Backup is in read-only mode\\.","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/MetadataManager.java","lineNumber":107,"sourceCode":"        }\n        try {\n            jsonObject = new JSONObject(metadataString);\n            if (!v5AndUp) {\n                // Meta is a subset of meta_v2.am.json except for backup_name\n                jsonObject.put(\"backup_name\", backupItem.getBackupName());\n            }\n            BackupMetadataV5.Metadata metadata = new BackupMetadataV5.Metadata(jsonObject);\n            return new BackupMetadataV5(backupInfo, metadata);\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for path \" + metadataFile, e);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static Map<String, String> writeMetadata(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {\n        if (!backupFile.isBackupMode()) {\n            throw new IOException(\"Backup is in read-only mode.\");\n        }\n        if (metadata.info.version >= 5) {\n            // v5 and up\n            return writeMetadataV5(metadata, backupFile);\n        } else {\n            // Old style backup\n            return writeMetadataV2(metadata, backupFile);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    private static Map<String, String> writeMetadataV2(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {\n        Path metadataFile = backupFile.getMetadataV2File();\n        try (OutputStream outputStream = metadataFile.openOutputStream()) {\n            JSONObject metadataObject = metadata.info.serializeToJson();\n            JSONUtils.putAll(metadataObject, metadata.metadata.serializeToJson());\n            // Info is a subset of meta_v2.am.json except for backup_name","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/MetadataManager.java#L89-L125","documentation":"writeMetadata refuses to write when the BackupItem is not in backup (writable) mode, throwing IOException \"Backup is in read-only mode.\" This protects restored/loaded backup views from being mutated accidentally.","triggerScenarios":"Calling writeMetadata with a BackupItem opened in restore/view mode (isBackupMode() == false), e.g. after loading an existing backup for reading rather than creating one during a backup operation.","commonSituations":"Trying to update metadata of an existing backup from a read-only viewer context, or reusing a BackupItem constructed for restore inside a metadata-editing flow.","solutions":["Ensure the BackupItem is created/opened in backup mode (set the backup mode flag before writing).","Write metadata only during an active backup/creation session, not when viewing or restoring an existing backup.","If you must edit an existing backup, re-create it via a new backup operation instead of mutating read-only state."],"exampleFix":"// before\nMetadataManager.writeMetadata(metadata, backupItem);\n// after\nif (!backupItem.isBackupMode()) {\n    throw new IllegalStateException(\"Cannot write metadata: backup opened in read-only mode\");\n}\nMetadataManager.writeMetadata(metadata, backupItem);","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean canWriteMetadata(BackupItems.BackupItem item) { return item.isBackupMode(); }","tryCatchPattern":"try {\n    MetadataManager.writeMetadata(metadata, backupFile);\n} catch (IOException e) {\n    if (\"Backup is in read-only mode.\".equals(e.getMessage())) {\n        // reopen the BackupItem in backup mode or inform the user\n    } else throw e;\n}","preventionTips":["Only write metadata within an active backup/creation session.","Check isBackupMode() before any metadata mutation.","Keep read-only viewers strictly read-only; re-create backups to modify them."],"tags":["backup","read-only","io","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}