SERVER_ERROR object too large for cache is the protocol-level error memcached returns when a store operation targets a value larger than the daemon’s configured maximum item size. The default ceiling is 1 MB (1048576 bytes), set by the -I flag. The store is rejected cleanly: nothing is written, and any pre-existing item under that key is left untouched. From the application’s side this is usually the first sign that something upstream is serializing more data than intended.
The server-side counter is store_too_large, a cumulative 64-bit counter in the standard stats output, alongside store_no_memory. Any non-zero rate is worth investigating. This is not transient or self-healing: the code path producing the oversized payload will keep producing it until the payload is fixed or the ceiling is raised.
This article covers what the error means mechanically, how to identify the offending payload, and the tradeoffs of the two real fixes: shrinking the payload (the default recommendation) or raising -I deliberately. Raising -I is not free. Pages are 1 MB each, and the slab allocator’s behavior changes when item sizes cross the chunk boundary.
What this means
Memcached memory is divided into pages, each 1 MB by default. Items live in slab classes sized by chunk size, grown by the -f factor (default 1.25). The maximum item size, set by -I, is enforced on every store operation. When a payload exceeds the configured ceiling, the daemon rejects the store and increments store_too_large.
The default of 1 MB reflects memcached’s design point: many small, fast objects. Large items consume whole pages, distort slab distribution, increase per-operation memory pressure, and at high enough throughput saturate network links. The error is the daemon refusing to let a single object distort the cache.
The exact string the client receives over the text protocol is SERVER_ERROR object too large for cache\r\n. The behavior is deterministic, not probabilistic. The same payload under the same -I will always fail.
Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Serialized object grew unexpectedly | A specific key or class of keys starts failing after a deploy; store_too_large climbs stepwise | Diff the recent application change against the cached object shape |
| Failed or skipped compression step | Items that used to fit now do not; client library shows compression disabled or erroring | Inspect the client’s serializer and compression configuration |
| Unbounded list cached whole | Counter climbs as the dataset grows over days or weeks; no recent deploy | Inspect the cached value: a list, feed, or result set with no cap |
-I lowered deliberately or by accident | All large-item stores fail at once after a config or upgrade event | Compare the running item_size_max against intended -I |
| Client library max value lower than server’s | Items under server -I still rejected; server store_too_large does not move | Check the client library’s own size cap |
Quick checks
All commands are read-only.
# Confirm memcached is up and identify version
echo "version" | nc -q1 localhost 11211
# Read the current max item size and connection limit
echo "stats settings" | nc -q1 localhost 11211 | grep -E "STAT (item_size_max|maxconns)"
# Check the store_too_large counter and its sibling
echo "stats" | nc -q1 localhost 11211 | grep -E "STAT store_(too_large|no_memory)"
# Confirm total memory budget and current usage
echo "stats" | nc -q1 localhost 11211 | grep -E "STAT (bytes |limit_maxbytes)"
# Per-slab view: see which classes hold large items
echo "stats slabs" | nc -q1 localhost 11211 | grep -E "(chunk_size|used_chunks|total_pages)"
# See eviction pressure per slab class (large-item classes sit at the top)
echo "stats items" | nc -q1 localhost 11211 | grep -E "(evicted|evicted_time|outofmemory)"
# Confirm slab_automove and slab_reassign state
echo "stats settings" | nc -q1 localhost 11211 | grep -E "slab_(automove|reassign)"
# See how the daemon was started, if reachable via the process table
ps -eo pid,cmd | grep '[m]emcached'
# Confirm the OS file descriptor limit is not the binding constraint
prlimit --pid "$(pgrep -x memcached)" --nofile
How to diagnose it
- Confirm
store_too_largeis actually moving. Sample twice with a known interval. A static non-zero value is a historical event; an increasing value is a live problem. - Confirm the configured ceiling matches what you expect.
stats settingsreportsitem_size_max. If it differs from intended, the daemon was started with a different-I, or a managed-service parameter group overrode it. - Capture the actual byte length of the value the application is trying to store. The server does not log rejected payloads. The diagnosis has to happen on the application side: instrument the serialization path to log key, value length, and a stack trace when the client returns this error.
- If you cannot instrument, reproduce the rejection manually with
nc. This writes a single test key with a 60-second TTL; the store is rejected by the server, so nothing is cached.
# Build a payload larger than the default 1 MB and try to set it
head -c 1100000 /dev/urandom | base64 > /tmp/big.txt
printf "set too_large_test 0 60 %d\r\n" "$(stat -c %s /tmp/big.txt)" | cat - /tmp/big.txt | nc -q1 localhost 11211
# Expect: SERVER_ERROR object too large for cache
rm /tmp/big.txt
- Use
stats slabsto verify the largest slab classchunk_sizeis consistent withitem_size_maxfromstats settings. Items aboveitem_size_maxare rejected unconditionally; this is the only condition that triggersstore_too_large. With large-item chunking (items aboveslab_chunk_max, default 16 KB), values betweenslab_chunk_maxanditem_size_maxspan multiple chunks. - Rule out
store_no_memory. If the daemon is running with-M(no-eviction mode),store_no_memoryrises alongside rejections. The fix path is different: that is memory exhaustion under explicit no-eviction policy, not oversized payloads. - Check the client library’s own size cap. Many client libraries enforce a max value independently of the server. A payload under the server’s
-Ican still be rejected client-side before the request reaches the network. This shows up as the same error class in application logs but no corresponding increment on the server’sstore_too_large.
flowchart td
A[store_too_large moving] --> B{item_size_max matches intended -I?}
B -- No --> C[Fix daemon flag or managed parameter group]
B -- Yes --> D{Payload legitimately needs to be large?}
D -- No --> E[Fix serialization: cap collections, restore compression]
D -- Yes --> F{Large items dominate the cache?}
F -- No --> G[Raise -I deliberately, plus client caps]
F -- Yes --> H[Move large items to extstore]
C --> I[Restart with a cache warmup plan]
G --> IMetrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
store_too_large | Direct counter of rejected oversized stores | Any non-zero rate; even single increments mean oversized items are being generated |
item_size_max (in stats settings) | The configured ceiling; confirms the running -I | Differs from intended configuration |
store_no_memory | Distinguishes oversize from -M mode memory exhaustion | Non-zero only when running with -M |
cmd_set rate | Denominator for the store failure ratio | store_too_large / cmd_set rising indicates a growing fraction of writes are oversized |
Per-slab chunk_size and used_chunks for the largest classes | Shows where oversized items would land | Largest slab class is full while smaller classes have headroom |
bytes_written / cmd_get | Average response size trend; large items also stress reads | Ratio climbing indicates value-size inflation generally |
| Client-side max value (library-specific) | Library cap independent of the server | Set below server -I, causing silent client-side rejects |
Fixes
Fix the payload (preferred)
Almost every occurrence of store_too_large traces back to one of three things in the application:
- A serialized object grew, typically because a field was added, a relation was eagerly loaded, or a format changed.
- A compression step that previously brought the payload under 1 MB was disabled, regressed, or never ran for this code path.
- An unbounded collection (a feed, a result set, a list of items) was cached whole instead of paginated or summarized.
The fix lives in the serialization path. Cap the collection. Drop fields the cache consumer does not need. Restore or add compression. Split the single large value into multiple smaller keys the application can read independently.
This fix has no memcached-side cost. It does not require a restart, and it does not distort slab distribution. It is the only fix that addresses the root cause rather than the symptom.
Raise -I deliberately (with tradeoffs)
If the payload genuinely must be large (a precomputed report, a rendered fragment, a media thumbnail set), raising -I is the alternative. The flag accepts values up to 1 GB.
What changes when -I exceeds 1 MB:
- The daemon emits a startup warning.
WARNING: Setting item max size above 1MB is not recommended!is expected and is not by itself a problem. - Large items no longer occupy one item per page. They span multiple slab chunks via the
slab_chunk_maxmechanism, introduced experimentally in 1.4.29. The default chunk size is 16 KB. An item requiring 16 KB + 1 byte consumes 32 KB. This rounding overhead is significant at smaller sizes. - Memory fragmentation becomes more visible. Freeing enough contiguous space for a 5 MB item when the cache is full of 100 KB items may require evicting many smaller items. In a cache that mixes very large and very small items, expect more evictions of small items than the global memory numbers would suggest.
- Concurrent uploads of large items are memory-hungry. Storing hundreds of megabytes in parallel requires hundreds of megabytes of chunk memory just to handle in-flight uploads. This can produce out-of-memory errors during read even when the cache appears to have headroom.
To raise -I:
- Pick the new ceiling based on the actual largest intended payload plus generous headroom. Do not pick 1 GB because it is the maximum. Pick the smallest value that fits real payloads.
- Update the daemon startup flags: systemd unit, supervisor config, container command, or managed-service parameter group.
- Restart memcached. This is a full data-loss event. Plan a warmup window.
- Update every client library’s own max value cap to match. A client-side cap below the server’s
-Iwill continue to reject payloads silently. - Watch
store_too_largedrop to zero, then watch eviction rate andevicted_timeover the next hours for signs the larger items are distorting the cache.
For managed memcached, the parameter is set via the provider’s parameter group, not the daemon command line. Managed providers may also impose different min and max bounds than open-source memcached.
Move large items to extstore
If the workload is dominated by a small number of very large items, extstore (1.5.4+) is a structurally cleaner answer than raising -I on the main slab allocator. Extstore spills large items to SSD, leaving RAM for the small, hot items that benefit from it. This adds disk I/O as a monitored resource and changes the failure surface: disk full, disk slow, SSD wear. The relevant stats are get_extstore, get_aborted_extstore, get_oom_extstore, recache_from_extstore, extstore_page_allocs, extstore_page_evictions, the extstore_objects_evicted/read/written/used family, and the extstore_bytes_* counters. Extstore is strictly opt-in and is not the right answer for every workload, but it is the right answer when large items are intentional and persistent.
What not to do: silent client-side truncation
Resist catching the error client-side and storing a truncated or empty value under the same key. Downstream readers will get the truncated payload with no signal that it was truncated. The cache will appear healthy while serving wrong data. If you must handle the error at the application layer, store under a different key, log the event, and emit a metric.
Prevention
- Alert on any non-zero rate of
store_too_large. Even single occurrences mean oversized items are being generated somewhere. This is one of the cleanest signals in memcached: it has no benign interpretation. - Track value-size distributions in the application. The server only tells you a payload was rejected. The application knows the shape of every payload it serializes. Log a histogram of serialized sizes and alert on the right tail.
- Pin serialization formats in tests. Most
store_too_largeregressions come from a deploy that added a field or removed a compression step. A unit test that asserts the serialized size of representative cached objects catches these before production does. - Cap collections before caching. Anywhere the application caches a list, feed, or result set, cap the count of items before serialization. An unbounded list cached whole is the most common cause of slow growth in
store_too_largeover weeks. - Treat raising
-Ias a capacity-planning decision. If you raise it, also raise the client-side caps, document the new ceiling, and add eviction-pressure monitoring for the large-item slab classes. - Review managed-service parameter groups after upgrades. Managed providers can reset or override
-Iduring maintenance windows in ways that differ from open-source behavior.
How Netdata helps
- The memcached collector surfaces
store_too_largeandstore_no_memoryas per-second counters, so non-zero rates are visible within seconds rather than after the next polling interval. - Correlating
store_too_largeagainstcmd_setrate gives the failure ratio in real time. A spike in rejections against a stable set rate points to a payload regression; a spike against a spike in set rate points to a new code path or bulk load. - The same collector exposes
item_size_maxfromstats settings, so a deliberate or accidental change to-Iis visible as a step in the chart, not a surprise during an incident. - Per-slab charts show whether large-item slab classes are coming under eviction pressure after a deliberate
-Iraise, before the global hit-ratio chart starts to degrade. bytes_writtenandcmd_getcharts side by side surface value-size inflation generally. If average response size is climbing in lockstep withstore_too_large, the same payload regression is also stressing reads.- Anomaly detection on
store_too_largeis useful precisely because the steady-state value should be zero. Any non-zero value is, by definition, anomalous for this metric.
Related guides
- Memcached evicted_unfetched and expired_unfetched: caching data nobody ever reads
- Memcached cas_badval climbing: check-and-set contention and lost updates
- Memcached connection refused: telling a dead process from a hung or full one
- Memcached evicted_time low: distinguishing healthy turnover from cache thrash
- Memcached eviction cascade: when a full cache overloads the backend
- Memcached evictions climbing: the cache is full and discarding live data
- Memcached high miss rate: separating cold start, new key patterns, and memory pressure
- How Memcached actually works in production: a mental model for operators
- Memcached incr/decr misses: evicted counters that silently break rate limiters and locks
- Memcached hit ratio dropping: reading get_hits, get_misses, and cache effectiveness
- Memcached monitoring checklist: the signals every production cache needs
- Memcached monitoring maturity model: from survival to expert






