Konloch/bytecode-viewer · error · IllegalArgumentException
factory doesn't key for key: ${key}
Error message
factory doesn't key for key: ${key} What it means
Thrown by AbstractLoaderFactory.unregister when no factory is registered under the given key. Unregister is intentionally strict: removing a key that is absent means caller state and registry state have diverged. (Note the message has a typo: "factory doesn't key for key".)
Source
Thrown at src/main/java/the/bytecode/club/bytecodeviewer/bootloader/loader/AbstractLoaderFactory.java:65
if (FACTORY_CACHE.containsKey(key))
{
throw new IllegalArgumentException("factory already registered with key: " + key);
}
FACTORY_CACHE.put(key, factory);
}
public static void unregister(String key)
{
if (key == null)
{
throw new IllegalArgumentException("null key");
}
if (!FACTORY_CACHE.containsKey(key))
{
throw new IllegalArgumentException("factory doesn't key for key: " + key);
}
FACTORY_CACHE.remove(key);
}
public static <T extends ExternalResource<?>> LoaderFactory<T> find()
{
return find(DEFAULT_KEY);
}
@SuppressWarnings("unchecked")
public static <T extends ExternalResource<?>> LoaderFactory<T> find(String key)
{
if (key == null)
{
throw new IllegalArgumentException("null key");
}
View on GitHub (pinned to 31430e0033)
Solutions
- Check registration existence before removing (or track keys you registered yourself).
- Make unregister idempotent in your code by catching/swallowing this specific case during teardown.
- Ensure only one cleanup path owns registry teardown.
Example fix
// before
tearDownHooks.forEach(k -> unregister(k));
// after
tearDownHooks.stream().filter(k -> isRegistered(k)).forEach(k -> unregister(k)); // or try { unregister(k); } catch (IllegalArgumentException e) { /* already gone */ } Defensive patterns
Strategy: try-catch
Validate before calling
// only unregister keys you registered yourself in this run if (myRegisteredKeys.remove(key)) AbstractLoaderFactory.unregister(key);
Try / catch
try { AbstractLoaderFactory.unregister(key); }
catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().startsWith("factory doesn't")) {
log.debug("already unregistered: {}", key); // idempotent teardown
} else throw e;
} Prevention
- Make teardown idempotent — double cleanup paths are common
- Let one owner (a single shutdown hook) manage registry lifecycle
- Treat unknown-key unregister during shutdown as a warning, not a crash
- Keep key strings in constants shared with register
When it happens
Trigger: Calling unregister("x") when "x" was never registered, was already unregistered (double teardown), or the static cache was cleared between registration and removal, e.g. two shutdown hooks both unregistering the same key.
Common situations: Application shutdown where cleanup runs twice (context close + JVM shutdown hook); test suites sharing a static registry across test classes; renaming a loader key in config without updating the unregister call.
Related errors
- null key or factory
- factory already registered with key: ${key}
- null key
- '${codebase}' is not a directory
- Unknown constant pool tag ${tag}
AI-assisted analysis of Konloch/bytecode-viewer@31430e0033 (2026-09-05).
Data as JSON: /api/errors/d5f3db92549f965e.
Report an issue: GitHub.