MuntashirAkon/AppManager · error · IOException

for file

Error message

 for file 

What it means

writeMetadataV5 writes meta_v5.am.json by serializing metadata.metadata via serializeToJson(); any JSONException is rethrown as IOException with the metadata file path appended, indicating the v5 metadata document could not be serialized to JSON.

Solutions

  1. Inspect the JSONException cause to find the field that failed to serialize and populate it with a valid value.
  2. Validate the Metadata object (required fields non-null) before calling writeMetadata.
  3. Reload the metadata from the source backup to recover a consistent in-memory object.

Example fix

// before
MetadataManager.writeMetadata(metadata, backupFile);
// after
if (metadata.metadata == null) {
    throw new IllegalArgumentException("Metadata body is null");
}
MetadataManager.writeMetadata(metadata, backupFile);
Defensive patterns

Strategy: validation

Validate before calling

if (metadata.metadata == null || metadata.info == null) {
    throw new IllegalArgumentException("Incomplete BackupMetadataV5");
}

Try / catch

try {
    MetadataManager.writeMetadata(metadata, backupFile);
} catch (IOException e) {
    if (e.getCause() instanceof JSONException) {
        // fix the offending Metadata field reported by the cause
    } else throw e;
}

Prevention

When it happens

Trigger: Calling writeMetadata for a v5+ backup when metadata.metadata.serializeToJson() throws — typically null or invalid field values inside the Metadata object.

Common situations: Programmatically constructed Metadata objects with missing/invalid fields (e.g. null timestamps or names placed where JSONObject.put rejects them), or corrupted in-memory metadata after partial deserialization.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/49d2ee0d1b1aa33d. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/backup/MetadataManager.java:143

            // Info is a subset of meta_v2.am.json except for backup_name
            metadataObject.remove("backup_name");
            outputStream.write(metadataObject.toString(4).getBytes());
            return Collections.singletonMap(metadataFile.getName(), DigestUtils.getHexDigest(
                    metadata.info.checksumAlgo, metadataFile));
        } catch (JSONException e) {
            throw new IOException(e.getMessage() + " for path " + backupFile.getBackupPath(), e);
        }
    }

    @WorkerThread
    @NonNull
    private static Map<String, String> writeMetadataV5(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {
        Map<String, String> filenameChecksumMap = new LinkedHashMap<>(2);
        Path metadataFile = backupFile.getMetadataV5File(true);
        try (OutputStream outputStream = metadataFile.openOutputStream()) {
            outputStream.write(metadata.metadata.serializeToJson().toString(4).getBytes());
        } catch (JSONException e) {
            throw new IOException(e.getMessage() + " for file " + metadataFile, e);
        }
        // Encrypt the metadata
        Path encryptedMetadataFile = backupFile.encrypt(new Path[]{metadataFile})[0];
        filenameChecksumMap.put(encryptedMetadataFile.getName(), DigestUtils.getHexDigest(
                metadata.info.checksumAlgo, encryptedMetadataFile));
        Path infoFile = backupFile.getInfoFile();
        try (OutputStream outputStream = infoFile.openOutputStream()) {
            outputStream.write(metadata.info.serializeToJson().toString(4).getBytes());
            filenameChecksumMap.put(infoFile.getName(), DigestUtils.getHexDigest(
                    metadata.info.checksumAlgo, infoFile));
        } catch (JSONException e) {
            throw new IOException(e.getMessage() + " for file " + infoFile, e);
        }
        return filenameChecksumMap;
    }

    private static void setCrypto(@NonNull BackupItems.BackupItem backupItem, @NonNull BackupMetadataV5.Info backupInfo) throws IOException {
        if (!CryptoUtils.isAvailable(backupInfo.crypto)) {

View on GitHub (pinned to 0152f468fc)