Tencent/tinker · error · IllegalArgumentException
obj: {} cannot be closed.
Error message
obj: {} cannot be closed. What it means
SharePatchFileUtil.closeQuietly only closes objects that are AutoCloseable or ZipFile; any other object triggers IllegalArgumentException('obj: X cannot be closed.'). This is a developer-programming guard: the utility refuses to pretend it closed something it has no idea how to close.
Source
Thrown at tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/SharePatchFileUtil.java:162
try {
((Closeable) obj).close();
} catch (Throwable ignored) {
// Ignored.
}
} else if (Build.VERSION.SDK_INT >= 19 && obj instanceof AutoCloseable) {
try {
((AutoCloseable) obj).close();
} catch (Throwable ignored) {
// Ignored.
}
} else if (obj instanceof ZipFile) {
try {
((ZipFile) obj).close();
} catch (Throwable ignored) {
// Ignored.
}
} else {
throw new IllegalArgumentException("obj: " + obj + " cannot be closed.");
}
}
public static final boolean isLegalFile(File file) {
return file != null && file.exists() && file.canRead() && file.isFile() && file.length() > 0;
}
/**
* For some special device whose dex2oat procedure is optimized for tinker. (e.g. vivo, oppo)
*
* Because these devices by-pass our dex2oat request, which cause vm to load tinker's dex with interpret-mode
* and generate nothing instead of a valid oat file. It's fine to skip the check so far.
*
* @param file
* @return
*/
public static final boolean shouldAcceptEvenIfIllegal(File file) {
final boolean isSpecialManufacturer =View on GitHub (pinned to 1b7ea02c23)
Solutions
- Pass the actual resource object (InputStream/OutputStream/RandomAccessFile/ZipFile — all AutoCloseable), not a wrapper or owner.
- If the class only has a bespoke close(), call it directly in your own try/finally instead of closeQuietly.
- Wrap the non-AutoCloseable resource in a small adapter implementing AutoCloseable that delegates to its close method.
Example fix
// before
SharePatchFileUtil.closeQuietly(someLegacyHandle); // IllegalArgumentException
// after
try {
someLegacyHandle.disconnect(); // its real release method
} catch (Throwable ignored) { } Defensive patterns
Strategy: validation
Validate before calling
if (!(obj instanceof AutoCloseable) && !(obj instanceof ZipFile)) {
throw new IllegalArgumentException("Not closeable: " + obj);
}
SharePatchFileUtil.closeQuietly(obj); Type guard
static boolean isCloseable(Object o) { return o instanceof AutoCloseable || o instanceof java.util.zip.ZipFile; } Prevention
- Only pass resources implementing AutoCloseable (or ZipFile) to closeQuietly.
- For legacy resources with bespoke close methods, call them in your own finally block.
- Fail fast in debug builds on non-closeable objects.
When it happens
Trigger: Calling closeQuietly(obj) with an object that implements neither AutoCloseable nor ZipFile — e.g. a legacy class exposing only a custom close()/release()/destroy() method, a plain wrapper, or a null-ish sentinel passed by mistake.
Common situations: Copy-pasting the closeQuietly call around streams from older APIs that pre-date AutoCloseable (some dalvik-era or vendor classes); passing a domain object instead of the resource it owns.
Related errors
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/19436b4fb62fb789.
Report an issue: GitHub.