Tencent/tinker · error · IllegalArgumentException
Bad mode: ${mode}
Error message
Bad mode: ${mode} What it means
TinkerZipFile's constructor only permits mode == OPEN_READ or mode == OPEN_READ|OPEN_DELETE; anything else throws IllegalArgumentException('Bad mode') before the file is opened. OPEN_DELETE makes the file delete-on-close. Passing plain 0, OPEN_DELETE alone, or invented flag values is rejected because the class only supports reading.
Source
Thrown at third-party/tinker-ziputils/src/main/java/com/tencent/tinker/ziputils/ziputil/TinkerZipFile.java:134
public TinkerZipFile(String name) throws IOException {
this(new File(name), OPEN_READ);
}
/**
* Constructs a new {@code ZipFile} allowing access to the given file.
*
* <p>UTF-8 is used to decode all comments and entry names in the file.
*
* <p>The {@code mode} must be either {@code OPEN_READ} or {@code OPEN_READ|OPEN_DELETE}.
* If the {@code OPEN_DELETE} flag is supplied, the file will be deleted at or before the
* time that the {@code ZipFile} is closed (the contents will remain accessible until
* this {@code ZipFile} is closed); it also calls {@code File.deleteOnExit}.
*
* @throws IOException if an {@code IOException} occurs.
*/
public TinkerZipFile(File file, int mode) throws IOException {
filename = file.getPath();
if (mode != OPEN_READ && mode != (OPEN_READ | OPEN_DELETE)) {
throw new IllegalArgumentException("Bad mode: " + mode);
}
if ((mode & OPEN_DELETE) != 0) {
fileToDeleteOnClose = file;
fileToDeleteOnClose.deleteOnExit();
} else {
fileToDeleteOnClose = null;
}
raf = new RandomAccessFile(filename, "r");
readCentralDir();
// guard.open("close");
}
/**
* Returns true if the string is null or 0-length.
* @param str the string to be examined
* @return true if str is null or zero length
*/View on GitHub (pinned to 1b7ea02c23)
Solutions
- Use exactly TinkerZipFile.OPEN_READ, or OPEN_READ|TinkerZipFile.OPEN_DELETE if you want delete-on-close.
- Reference the constants from TinkerZipFile itself, not from java.util.zip.ZipFile or literal ints.
- If you constructed a combined mode variable, assert (mode & ~OPEN_DELETE) == OPEN_READ before calling the constructor.
Example fix
// before new TinkerZipFile(new File(path), ZipFile.OPEN_READ | someFlag); // after new TinkerZipFile(new File(path), TinkerZipFile.OPEN_READ);
Defensive patterns
Strategy: validation
Validate before calling
int mode = TinkerZipFile.OPEN_READ;
if (deleteOnClose) {
mode |= TinkerZipFile.OPEN_DELETE;
}
assert (mode & ~TinkerZipFile.OPEN_DELETE) == TinkerZipFile.OPEN_READ;
TinkerZipFile zf = new TinkerZipFile(file, mode); Prevention
- Build the mode only from TinkerZipFile's own constants.
- Never import ZipFile constants from java.util.zip for this class.
- Assert the mode shape in debug builds to catch flag-combination regressions.
When it happens
Trigger: new TinkerZipFile(file, mode) with mode outside {OPEN_READ, OPEN_READ|OPEN_DELETE} — e.g. mode = 0, mode = OPEN_DELETE without OPEN_READ, or OR-ing in a write flag from java.util.zip.ZipFile (this class has no write mode).
Common situations: Copying constructor calls from code that targeted java.util.zip.ZipFile with different constants; building the mode dynamically from user flags where the read bit can end up unset; version differences where a constant moved between classes.
Related errors
- ${argument} too long: ${bytes.length}
- Bad CRC32: ${value}
- Extra data too long: ${data.length}
- Bad method: ${value}
- Bad size: ${value}
AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14).
Data as JSON: /api/errors/2b99f88ca59cbf90.
Report an issue: GitHub.