elastic/elasticsearch · error · PainlessError
script allocation limit exceeded: allocation of [{}] bytes b
Error message
script allocation limit exceeded: allocation of [{}] bytes brings the running total to [{}] bytes, over the limit of [{}] bytes What it means
AllocationGuard.allocationLimitExceeded is the hard stop for the Painless per-context memory budget. Each significant allocation inside a running script is charged against a byte limit (script.painless.max_allocation_bytes, default disabled at -1b but commonly capped). When an allocation pushes the running total past the limit, the guard logs a warning and throws a PainlessError — a Throwable that is not normally catchable in the script, aborting execution.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/AllocationGuard.java:70
/**
* Logs a {@code WARN} and throws a {@link PainlessError} describing an allocation that pushed a script over its limit.
* {@link PainlessError} is an {@link Error}, so it cannot be caught from Painless source. Never returns normally. The
* specific allocation that crossed the limit is not reported: it is whichever happened to tip the running total, not
* necessarily the dominant cost, so naming it would mislead more than help.
*
* @param attemptedBytes the size of the allocation that tripped the limit
* @param totalBytes the running total after charging the allocation
* @param limitBytes the per-context limit
*/
public static void allocationLimitExceeded(long attemptedBytes, long totalBytes, long limitBytes) {
logger.warn(
"Painless script allocation limit exceeded: allocation of [{}] bytes brings running total to [{}] bytes (limit [{}] bytes)",
attemptedBytes,
totalBytes,
limitBytes
);
throw new PainlessError(
"script allocation limit exceeded: allocation of ["
+ attemptedBytes
+ "] bytes brings the running total to ["
+ totalBytes
+ "] bytes, over the limit of ["
+ limitBytes
+ "] bytes"
);
}
}
View on GitHub (pinned to db6a809a66)
Solutions
- Raise script.painless.max_allocation_bytes (cluster setting) within the allowed range [1b, 1gb] to fit the script's working set, or set -1b to disable.
- Rewrite the script to stream/accumulate less: use StringBuilder with sized capacity, avoid intermediate copies, prefer doc-values direct reads, and narrow the query to reduce processed docs.
- Move the heavy transformation out of Painless into an ingest pipeline processor or application code.
- Profile by enabling the guard at a low threshold and bisecting which allocation trips it.
Example fix
// before (script_fields, builds huge string)
"script": { "source": "String s = ''; for (int i = 0; i < 100000; i++) { s += i } return s" }
// after (bounded, or raise setting)
PUT _cluster/settings
{ "persistent": { "script.painless.max_allocation_bytes": "256mb" } }
// and/or rewrite to avoid O(n^2) concatenation Defensive patterns
Strategy: validation
Validate before calling
// Estimate script working set before deploying; or check the setting is adequate
async function checkAllocationBudget(client, estimatedBytes) {
const settings = await client.cluster.getSettings({ include_defaults: true });
const max = (settings.persistent['script.painless.max_allocation_bytes']
|| settings.defaults['script.painless.max_allocation_bytes']);
if (max && max !== '-1b' && parseBytes(max) < estimatedBytes) {
throw new Error(`Estimated allocation ${estimatedBytes} exceeds ${max}; raise the setting or rewrite the script`);
}
}
function parseBytes(s){ /* parse '64mb' -> number */ } Try / catch
// ScriptException/PainlessError is not safely catchable in-script; catch at the API call boundary:
// try { await client.search({body}) } catch (e) { if (/allocation limit exceeded/.test(e.message)) { /* rewrite script or raise setting */ } } Prevention
- Profile scripts on a representative dataset before production.
- Set a conservative max_allocation_bytes on shared clusters and monitor warnings.
- Avoid O(n^2) string concatenation; use StringBuilder or pre-sized collections.
- Narrow queries to reduce docs processed per script execution.
When it happens
Trigger: A Painless script (runtime, ingest, or script_fields) that allocates large buffers: building big strings via concatenation in a loop, List.of/Map.of with many entries, copying large doc values, or accumulating results. The per-context budget is exceeded mid-execution. Reproducible by raising script.painless.max_allocation_bytes and seeing the script succeed, lowering it and seeing it fail.
Common situations: Aggregations or runtime fields that materialize large collections. Ingest pipelines with grok/csv on huge documents. Scripts that join strings across many docs. Lowering the allocation setting for safety on shared clusters. Version upgrades that changed default allocation charging.
Related errors
- dynamic method [{}, {}/{}] not found
- Illegal list shortcut value [{}].
- dynamic getter [{}, {}] not found
- Illegal list shortcut value [name].
- dynamic setter [receiverClass, name] not found
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/ea35d61a3ebcb154.
Report an issue: GitHub.