Kubernetes object size limits
On this page
A Helm upgrade fails with this message:
Error: UPGRADE FAILED: cannot patch "app-settings" with kind ConfigMap:
ConfigMap "app-settings" is invalid: []: Too long: may not be more than 1048576 bytes
1,048,576 is 1024 × 1024, so the limit is 1 MiB. Kubernetes refused to store the object because it’s too big. Nothing is wrong with Helm, the pod, or the node, and retrying won’t help. The object has to get smaller.
A few terms
- Object: a record stored in a Kubernetes cluster that describes something that should exist, such as a running app, a group of settings, or a password. Objects are usually written as YAML files.
- API server: the part of Kubernetes that every change goes through [1]. It checks each object before saving it, and the error above comes from that check.
- etcd: the database where the API server keeps every object [1].
- ConfigMap: an object that holds settings as keys and values, for an app to read as environment variables or files. It isn’t meant for large data, and its data can’t exceed 1 MiB [2].
- Secret: the same idea for sensitive values like passwords and keys, with the same 1 MiB limit [3].
- Helm: a tool that installs apps into Kubernetes from a chart, a package of templates for all the objects an app needs [4]. A values file (usually
values.yaml) fills in the templates. A release is one installed copy of a chart, and every install, upgrade, or rollback adds a new revision of it [4], [5]. - MiB and MB: a mebibyte (MiB) is 1,048,576 bytes and a megabyte (MB) is 1,000,000. Kubernetes counts in bytes, and 1 MB of data fits under the limit while 1.1 MB doesn’t.
Where the limit is checked
Every object passes the same check on its way into the cluster. During a Helm upgrade, two kinds of object go through it: the ones your chart defines, and a record Helm keeps about the release itself.
Both kinds of object pass the same check. Helm saves its release record before it applies the chart's objects, so a release record that's too big fails the upgrade before any of them change.
The check adds up the values under data (and binaryData, for a ConfigMap), not the keys or the YAML around them, and compares the total with 1,048,576 bytes [6]. etcd has limits of its own, which the 1 MiB check stays safely under: by default it accepts requests up to 1.5 MiB and stores up to 2 GiB in total, with 8 GiB as the suggested maximum [7]. That total is why lots of objects that each fit can still cause trouble together.
The rendered size is the size that counts
The object Kubernetes checks is the one Helm produces from the templates, not any file you edited. Templates can repeat their input, so a modest values file can render into an object far bigger than anything in the repo:
Nobody edited a file anywhere near 1 MiB. The loop did the multiplying, and only the rendered object shows it.
To see the real size, render just the suspect template and count its bytes:
macOS / Linux
helm template ./chart -f values.yaml --show-only templates/settings-configmap.yaml | wc -c
Windows (PowerShell)
$out = helm template ./chart -f values.yaml --show-only templates/settings-configmap.yaml | Out-String
[Text.Encoding]::UTF8.GetByteCount($out)
helm template renders the chart locally without touching the cluster, and --show-only keeps just the one file [8]. wc -c counts bytes. In PowerShell, Out-String joins the output into one string [9] and GetByteCount counts the bytes it takes as UTF-8 [10]. Either way the count includes the YAML around the data, so it reads a little high, and a number under 1,048,576 is safely under the limit.
Helm’s release record hits the same limit
Helm keeps a record of every release revision, and by default that record is a Secret in the release’s namespace, holding the contents of the chart and the values [11]. Its name follows the pattern sh.helm.release.v1.<release>.v<revision> [12]. Being a Secret, it gets the same 1 MiB check, and the error names that Secret instead of your ConfigMap.
Two details change how this one behaves:
- It fails first. During an upgrade, Helm saves the new release record before it applies any of the chart’s objects [13]. A record that’s too big stops the upgrade before anything in the cluster changes.
- It’s compressed. Helm gzips the record and then base64-encodes it [14]. Compression usually makes the record much smaller than the chart, but base64 adds about a third back, so a chart whose contents are large even after compression hits the limit this way.
For release records that really are that large, Helm documents a beta sql storage backend that keeps them in a database instead of the cluster [11].
Ways to get under the limit
| Option | Fits when | Cost |
|---|---|---|
| Shrink the template | A loop repeats a large block | Often the cheapest fix, so look here first |
| Split into several ConfigMaps | The content separates cleanly, such as per component | More objects, each mounted separately |
| Mount a volume or use an object store | The data is large reference data, not settings | A storage dependency and a loading step |
| Fetch at startup | The data changes independently of deploys | Pods depend on that source to start |
Moving the data to a Secret doesn’t help. Kubernetes doesn’t compress Secrets, and the base64 you see in a Secret’s YAML is only how the bytes are written down: the check counts the decoded bytes under data, against the same 1,048,576 [15]. Helm’s release record is smaller than its contents only because Helm compresses it before saving it.
Compressing the data yourself
Helm gets its release record under the limit by compressing it, and an app can do the same with its own data: gzip it, store the compressed bytes under the ConfigMap’s binaryData, which holds raw bytes rather than text [2], and decompress it when it’s read. At least one product documents this as its answer to the limit. Airlock Microgateway accepts zstd, gzip, or zip files as binaryData in its ConfigMaps, warns that decompressing costs extra resources, and recommends it only for a ConfigMap that would otherwise be over the limit [16].
That works there because the gateway was built to decompress its own config. For your own app, nothing in Kubernetes decompresses anything, so the app or a startup step has to do it, and I haven’t found a source covering that in general. It also only helps if the data compresses well, and diffs of compressed bytes stop being readable in review.
The Kubernetes docs point the same way for settings larger than the limit: a mounted volume, a database, or a file service [2]. Start with the template, though. If the rendered output holds the same block many times, include it once and reference it, and the object may drop well under the limit with no change to how the app works.
References
Show all 16 sourcesHide sources
- [1] ↩ a b The Kubernetes Authors, “Kubernetes Components,” Kubernetes Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/overview/components/
- [2] ↩ a b c The Kubernetes Authors, “ConfigMaps,” Kubernetes Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/configuration/configmap/
- [3] ↩ The Kubernetes Authors, “Secrets,” Kubernetes Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://kubernetes.io/docs/concepts/configuration/secret/
- [4] ↩ a b The Helm Authors, “Introduction to Helm,” Helm Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://helm.sh/docs/intro/introduction/
- [5] ↩ The Helm Authors, “Using Helm,” Helm Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://helm.sh/docs/intro/using_helm/
- [6] ↩ The Kubernetes Authors, “pkg/apis/core/validation/validation.go (ValidateConfigMap),” kubernetes/kubernetes, GitHub repository, commit ef06af9. Accessed: Oct. 9, 2026. [Online]. Available: https://github.com/kubernetes/kubernetes/blob/ef06af9b9d09e8dc0eb1cc0768b0b542f35549bb/pkg/apis/core/validation/validation.go#L8204-L8232
- [7] ↩ The etcd Authors, “System limits,” etcd v3.5 Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://etcd.io/docs/v3.5/dev-guide/limit/
- [8] ↩ The Helm Authors, “helm template,” Helm Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://helm.sh/docs/helm/helm_template/
- [9] ↩ Microsoft, “Out-String,” PowerShell 7.6 Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/out-string
- [10] ↩ Microsoft, “Encoding.GetByteCount Method,” .NET API Reference. Accessed: Oct. 9, 2026. [Online]. Available: https://learn.microsoft.com/en-us/dotnet/api/system.text.encoding.getbytecount
- [11] ↩ a b The Helm Authors, “Storage backends,” Helm Documentation, Advanced Helm Techniques. Accessed: Oct. 9, 2026. [Online]. Available: https://helm.sh/docs/topics/advanced/
- [12] ↩ The Helm Authors, “pkg/storage/storage.go (makeKey),” helm/helm, GitHub repository, commit dc56a44. Accessed: Oct. 9, 2026. [Online]. Available: https://github.com/helm/helm/blob/dc56a44fee5ac036807348bc48653bc93d714953/pkg/storage/storage.go#L339-L341
- [13] ↩ The Helm Authors, “pkg/action/upgrade.go,” helm/helm, GitHub repository, commit dc56a44. Accessed: Oct. 9, 2026. [Online]. Available: https://github.com/helm/helm/blob/dc56a44fee5ac036807348bc48653bc93d714953/pkg/action/upgrade.go#L408-L470
- [14] ↩ The Helm Authors, “pkg/storage/driver/util.go (encodeRelease),” helm/helm, GitHub repository, commit dc56a44. Accessed: Oct. 9, 2026. [Online]. Available: https://github.com/helm/helm/blob/dc56a44fee5ac036807348bc48653bc93d714953/pkg/storage/driver/util.go#L36-L58
- [15] ↩ The Kubernetes Authors, “pkg/apis/core/validation/validation.go (ValidateSecret),” kubernetes/kubernetes, GitHub repository, commit ef06af9. Accessed: Oct. 9, 2026. [Online]. Available: https://github.com/kubernetes/kubernetes/blob/ef06af9b9d09e8dc0eb1cc0768b0b542f35549bb/pkg/apis/core/validation/validation.go#L8101-L8115
- [16] ↩ Ergon Informatik AG, “ConfigMaps size limit,” Airlock Microgateway 4.7 Documentation. Accessed: Oct. 9, 2026. [Online]. Available: https://docs.airlock.com/microgateway/4.7/index/1730261073553.html
Every source cited across the primers is collected on one page.