asLody/VirtualApp · warning · IOException

Couldn't append

Error message

Couldn't append 

What it means

AtomicFile.truncate() opens the base file for output to zero it out. On FileNotFoundException it throws IOException 'Couldn't append <path>' (message wording is misleading — this is an open/create failure, not append). The generic IOException from sync/close is swallowed.

Solutions

  1. Ensure the file's parent directory and file exist (call startWrite/newFile once) before truncate
  2. Check write permission/storage state for the base path
  3. Wrap truncate in try-catch and recreate the AtomicFile from a valid directory

Example fix

// before
atomicFile.truncate(); // FileNotFoundException if file/dir missing
// after
File parent = base.getParentFile();
if (!parent.exists()) parent.mkdirs();
if (!base.exists()) base.createNewFile();
atomicFile.truncate();
Defensive patterns

Strategy: validation

Validate before calling

File base = ...;
if (!base.exists()) {
    base.getParentFile().mkdirs();
    base.createNewFile();
}

Try / catch

try {
    atomicFile.truncate();
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Couldn't append")) {
        // file missing: recreate via startWrite before truncating
    }
}

Prevention

When it happens

Trigger: Calling truncate() when mBaseName cannot be opened for writing: parent directory missing, storage read-only, or the file path is not writable by the app uid.

Common situations: Truncating before any startWrite ever created the file/directory; sdcard unmounted; path moved after refactor.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09). Data as JSON: /api/errors/1378d1ee2d70f577. Report an issue: GitHub.

Appendix: source

Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/AtomicFile.java:196

                    System.arraycopy(data, 0, newData, 0, pos);
                    data = newData;
                }
            }
        } finally {
            stream.close();
        }
    }

    /**
     * @deprecated This is not safe.
     */
    public void truncate() throws IOException {
        try {
            FileOutputStream fos = new FileOutputStream(mBaseName);
            fos.getFD().sync();
            fos.close();
        } catch (FileNotFoundException e) {
            throw new IOException("Couldn't append " + mBaseName);
        } catch (IOException e) {
        }
    }

    /**
     * @deprecated This is not safe.
     */
    @Deprecated public FileOutputStream openAppend() throws IOException {
        try {
            return new FileOutputStream(mBaseName, true);
        } catch (FileNotFoundException e) {
            throw new IOException("Couldn't append " + mBaseName);
        }
    }

    static boolean sync(FileOutputStream stream) {
        try {
            if (stream != null) {

View on GitHub (pinned to 666fefcb5d)