mybatis/mybatis-3 · error · CacheException
Cache instances require an ID.
Error message
Cache instances require an ID.
What it means
Thrown by PerpetualCache.equals() when the cache's id is null. Cache identity in mybatis is its id (namespace); equals() refuses to compare a cache that never got one. In practice ids are assigned by the builder (MapperBuilderAssistant.useNewCache passes the namespace), so a null id means a cache was constructed directly via new PerpetualCache(null) — almost always in custom cache code or tests.
Source
Thrown at src/main/java/org/apache/ibatis/cache/impl/PerpetualCache.java:70
@Override
public Object getObject(Object key) {
return cache.get(key);
}
@Override
public Object removeObject(Object key) {
return cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
@Override
public boolean equals(Object o) {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
if (this == o) {
return true;
}
if (!(o instanceof Cache)) {
return false;
}
Cache otherCache = (Cache) o;
return getId().equals(otherCache.getId());
}
@Override
public int hashCode() {
if (getId() == null) {
throw new CacheException("Cache instances require an ID.");
}
return getId().hashCode();View on GitHub (pinned to 008069adb1)
Solutions
- Always construct caches with a non-null id: new PerpetualCache("com.acme.UserMapper")
- In custom decorators, delegate getId() to the wrapped cache instead of constructing a fresh id-less one
- Assert cache.getId() != null in test fixtures before comparing caches
Example fix
// before
Cache cache = new PerpetualCache(null);
Set<Cache> caches = new HashSet<>(); caches.add(cache);
// after
Cache cache = new PerpetualCache("com.acme.UserMapper");
Set<Cache> caches = new HashSet<>(); caches.add(cache); Defensive patterns
Strategy: validation
Validate before calling
if (cache.getId() == null) throw new IllegalStateException("cache constructed without an id (namespace)"); Type guard
static boolean hasCacheId(Cache c) { return c != null && c.getId() != null && !c.getId().isEmpty(); } Prevention
- Never construct PerpetualCache/custom caches without a namespace id
- Custom decorators: forward getId() to the delegate
When it happens
Trigger: new PerpetualCache(null) (or a custom Cache with null id) followed by any equals() comparison — putting it in a Set/Map key, configuration.addCache comparisons, or test assertions. Framework-built caches always carry the namespace id, so this is a hand-construction problem.
Common situations: Unit tests constructing caches without ids; custom CacheDecorator wrappers that forward to a delegate created with a null id; copy-pasted cache factory code that forgets the id argument.
Related errors
- cache-ref element requires a namespace attribute.
- No cache for namespace '{namespace}' could be found.
- Cache-ref not yet resolved
- Should be specified either value() or name() attribute in th
- Cannot use both value() and name() attribute in the @CacheNa
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/730005677fdcaef0.
Report an issue: GitHub.