apache/hadoop · error · LimitExceededException
Too many counters: ${size} max=${countersMax}
Error message
Too many counters: ${size} max=${countersMax} What it means
Limits enforces the configured maximum number of counters in a Counters object: mapreduce.job.counters.max, default 120 (MRJobConfig.COUNTERS_MAX_DEFAULT). checkCounters throws LimitExceededException("Too many counters: N max=M") when the size crosses the cap, caches the violation in firstViolation, and rethrows the same exception on every subsequent limits check - so the job fails at the next counter operation, not just once. Note Limits.init is static-once per JVM, so the limits in effect are those of the first Configuration seen.
Source
Thrown at hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-core/src/main/java/org/apache/hadoop/mapreduce/counters/Limits.java:97
}
return COUNTERS_MAX;
}
public static String filterName(String name, int maxLen) {
return name.length() > maxLen ? name.substring(0, maxLen - 1) : name;
}
public static String filterCounterName(String name) {
return filterName(name, getCounterNameMax());
}
public static String filterGroupName(String name) {
return filterName(name, getGroupNameMax());
}
public synchronized void checkCounters(int size) {
if (firstViolation != null) {
throw new LimitExceededException(firstViolation);
}
int countersMax = getCountersMax();
if (size > countersMax) {
firstViolation = new LimitExceededException("Too many counters: "+ size +
" max="+ countersMax);
throw firstViolation;
}
}
public synchronized void incrCounters() {
checkCounters(totalCounters + 1);
++totalCounters;
}
public synchronized void checkGroups(int size) {
if (firstViolation != null) {
throw new LimitExceededException(firstViolation);
}View on GitHub (pinned to 2add963021)
Solutions
- Raise the cap on the job configuration: conf.setInt("mapreduce.job.counters.max", <needed>) (and mapreduce.job.counters.groups.max if groups also grow).
- Replace dynamic counter names with a fixed vocabulary and aggregate in your own code or a metrics system.
- Audit cardinality before submission: enumerate the counter names your mappers/reducers can emit.
- Remove or gate third-party libraries that register unbounded counters.
Example fix
// before: unbounded cardinality
context.getCounter("stats", "key-" + rawKey).increment(1);
// after: fixed vocabulary (preferred)
context.getCounter("stats", "distinct-keys").increment(1);
// or, if genuinely needed, raise the cap:
conf.setInt("mapreduce.job.counters.max", 1000);
conf.setInt("mapreduce.job.counters.groups.max", 200); Defensive patterns
Strategy: validation
Validate before calling
int countersMax = conf.getInt("mapreduce.job.counters.max", 120);
Set<String> plannedNames = /* enumerate every counter name your job can emit */;
if (plannedNames.size() > countersMax) {
throw new IllegalStateException("Job emits " + plannedNames.size()
+ " counters; raise mapreduce.job.counters.max or reduce cardinality");
} Try / catch
catch (LimitExceededException e) when merging/aggregating counters: stop merging, keep the already-aggregated partial counters, and log the overflow source - the limit re-throws on every later check until the Counters object is reset.
Prevention
- Fix counter-name cardinality at design time; counters are for bounded aggregates, not per-record keys.
- Set mapreduce.job.counters.max/groups.max explicitly in job conf instead of relying on the 120/50 defaults.
- Call Limits.init(conf) early with the intended Configuration (limits are static-once per JVM).
When it happens
Trigger: incrCounters()/checkCounters() exceeding mapreduce.job.counters.max - e.g. a job whose user counters have dynamic names (per-key, per-minute, per-tenant), or counter aggregation on the ApplicationMaster merging per-task counters past the cap.
Common situations: Jobs using counter names with unbounded cardinality; stacked libraries each registering many counters; clusters that lowered the default limits; upgrades where jobs newly exceed 120 counters and fail during merge with 'Too many counters'.
Related errors
- Too many counter groups: ${size} max=${groupsMax}
- Too many spill files got created, control it with mapreduce.
- Invalid specification for distributed-cache artifacts of typ
- Unable to parse '{}' as a URI, check the setting for mapredu
- Could not locate MapReduce framework name '{}' in mapreduce.
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/db223a4830af4bdc.
Report an issue: GitHub.