HMCL-dev/HMCL · error · IllegalArgumentException
Theme-pack asset entry contains a control character:
Error message
Theme-pack asset entry contains a control character:
What it means
Asset entry names must not contain ISO control characters (including NUL). If any character in a segment is a control char, normalizeEntryName throws IllegalArgumentException("Theme-pack asset entry contains a control character: <name>"). Control characters are unsafe in ZIP entry names and file lookups.
Solutions
- Trim the entry name and strip control characters before use (e.g. name.chars().filter(c -> !Character.isISOControl(c)))
- Fix the source that produced the dirty name (read lines, trim, decode correctly)
- Regenerate/repair the theme pack manifest with clean names
Example fix
// before ThemePackAsset.of(line); // line ends with '\n' // after ThemePackAsset.of(line.strip());
Defensive patterns
Strategy: validation
Validate before calling
static String stripControlChars(String name) {
return name.chars().filter(c -> !Character.isISOControl(c))
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString().strip();
} Type guard
static boolean hasNoControlChars(String s) {
return s.chars().noneMatch(Character::isISOControl);
} Try / catch
try {
ThemePackAsset.of(entryName);
} catch (IllegalArgumentException e) {
log.warn("Rejected asset entry with control chars: " + e.getMessage());
} Prevention
- Trim lines read from manifests before using them as entry names
- Decode names from bytes with the correct charset
- Sanitize or reject names containing NUL or control characters
When it happens
Trigger: Passing entry names containing characters like \0, \n, \t, or other ISO control codes to ThemePackAsset / normalizeEntryName, e.g. names parsed from binary data or with a trailing newline.
Common situations: Reading entry names from a raw byte stream or a file line with an untrimmed newline; corrupted or crafted pack manifests.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Theme-pack asset entry is empty
- Theme-pack asset entry must be relative:
- Theme-pack asset entry must be under assets/:
- Theme-pack asset entry must be a file:
- Theme-pack author must be an object or a string
AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10).
Data as JSON: /api/errors/da4c0a72aa60ee6f.
Report an issue: GitHub.
Appendix: source
Thrown at HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackAsset.java:81
}
if (normalized.startsWith("/") || normalized.matches("^[A-Za-z]:.*")) {
throw new IllegalArgumentException("Theme-pack asset entry must be relative: " + entryName);
}
if (!normalized.startsWith(ASSETS_PREFIX)) {
throw new IllegalArgumentException("Theme-pack asset entry must be under assets/: " + entryName);
}
if (normalized.endsWith("/")) {
throw new IllegalArgumentException("Theme-pack asset entry must be a file: " + entryName);
}
for (String segment : normalized.split("/")) {
if (segment.isEmpty() || ".".equals(segment) || "..".equals(segment)) {
throw new IllegalArgumentException("Theme-pack asset entry contains an unsafe segment: " + entryName);
}
for (int i = 0; i < segment.length(); i++) {
char ch = segment.charAt(i);
if (Character.isISOControl(ch) || ch == '\0') {
throw new IllegalArgumentException("Theme-pack asset entry contains a control character: " + entryName);
}
}
}
return normalized;
}
}
View on GitHub (pinned to 24702dc5a0)