ErrLookup › Background articles › "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank
"missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank
"Missing required config value", "cannot be blank", "requires ... configured" — errors of the missing-config-value family appear when a library reads a configuration key at startup or first use and finds it null, empty, whitespace-only, or absent, and refuses to guess a default. This article explains the mechanisms behind these fail-fast guards across Vector, Chroma, Hadoop, Maven, NATS, and dozens of other projects, and how to fix and prevent them.
Distilled from 98 documented records across 48 repositories.
Background
Every library in this family hits the same wall from a different direction: code that needs a value reaches for it — through an explicit require() accessor, a null/empty check, a paired-key XOR test, or a lookup into a config map — and finds nothing usable. Rather than continue with a guessed default, the code raises immediately. Chroma's Settings.require(key) raises ValueError when a required, default-less setting is None; Hadoop's RegistrySecurity.getOrFail throws IOException naming the exact missing key; Maven's toolchain factory aborts with MisconfiguredToolchainException when a <provides> token has no value or a jdk toolchain lacks its <jdkHome> block; Nginx Proxy Manager's generateDbConfig throws when the "database" key is absent entirely. The common design decision is that an empty string is treated as missing: Hadoop's StorageSize.parse rejects blank input with "value cannot be blank", ZeroClaw trims whitespace before deciding a value like model_provider or heartbeat agent is empty, and Hadoop's NamedCommitterFactory rejects blank committer classnames the same way it rejects absent ones.
The layer that produces the error varies with when the value is consumed. Many checks fire at construction or boot: NATS validates JetStream clustering preconditions (cluster name, routes, or a system-account leafnode share) while enabling the feature, ZeroClaw's Nevis auth provider fails in its constructor when local token validation lacks a jwks_url, and LiveKit's TURN server construction fails when RTC node IP config for a bind address family is empty. Others fire lazily at first use — Nginx Proxy Manager's missing-database error is thrown the first time the database singleton is requested, Puppet's "Mounts without paths are not usable" can surface at request time when a client actually hits a pathless fileserver mount, and Vector's log-schema expectation only detonates when a docker_logs merge path actually executes. That timing difference matters for debugging: boot-time errors are easy to attribute, while lazy errors can look like failures of the feature rather than of configuration.
These are deliberately defensive guards, not accidents. The documentation across records repeatedly stresses why the code refuses to guess: NATS needs a stable cluster name so raft peer identity survives restarts; ZeroClaw's heartbeat has deliberately no default-agent fallback so it never pings from an unintended workspace; Chroma's require() distinguishes "nobody supplied it" from "optional"; Dgraph's JWT verifier refuses when the algorithm is unset because it cannot know which signing algorithm to enforce. The error text often doubles as documentation — several messages embed the exact fix, like ZeroClaw's AIEOS error printing a copy-pastable config snippet or its TTS error spelling out the exact config join.
Across the 48 repositories, the family varies mainly in what counts as "missing" and where the truth lives. Sources range from YAML/TOML files (Vector's log_schema, Grav's backups.profiles, ZeroClaw's zeroclaw.toml), environment variables (Chroma's CHROMA_-prefixed vars, where a template rendering to "" produces an empty value), .env files loaded relative to the working directory, XML (Maven's toolchains.xml, Hadoop's core-site.xml), JSON (Nginx Proxy Manager's config.json), and interactive prompts (oh-my-pi's blank custom URL answer). Some errors guard simple scalar keys; others guard cross-key invariants — Hadoop's OBS proxy requires username and password together, Fluentd's time_type mixed requires at least one format, MLflow's sanitize guardrail requires an action LLM endpoint. A recurring trap is that defaults themselves can be the problem: Hadoop's registry digest credentials default to empty strings, so merely enabling digest mode triggers the throw, while other libraries (Hadoop's static web user, Vector's message key) have non-empty defaults that only break when explicitly blanked.
Common causes
- Key never set in the config file. The config file or section simply omits the required key — no "database" block in config.json, no [heartbeat] agent in zeroclaw.toml, a jdk toolchain without a <configuration> block. This is the plainest case: the application was started from a fresh clone or minimal template without following setup docs.
- Key present but empty or whitespace-only. Nearly all of these libraries treat "", whitespace, or an XML element like <vendor/> as missing. Hadoop's StorageSize.parse rejects blank input outright; ZeroClaw trims agent model_provider and heartbeat agent values before deciding they're empty; Maven rejects provides tokens with null values.
- Environment variable missing or rendering to empty. A CHROMA_-prefixed env var is misspelled or absent, or an env-var template in the config renders to "" (Vector's log_schema.message_key case). Chroma's .env file is also loaded relative to the working directory, so running from a different directory silently loads nothing.
- Paired or dependent keys where only one was set. Several configs enforce cross-key invariants: Hadoop's OBS proxy requires fs.obs.proxy.username and fs.obs.proxy.password together (XOR check); NATS JetStream clustering needs a cluster name plus routes or a system-account leafnode; Fluentd's time_type mixed requires time_format or time_format_fallbacks; ZeroClaw's identity format="aieos" requires aieos_path or aieos_inline. Setting one side and forgetting the other triggers the guard.
- Default that turns out to be empty. Some guarded keys default to empty strings, so enabling the feature that reads them is enough to trigger the error — Hadoop registry digest credentials default to ''. Conversely, keys with non-empty defaults (Hadoop's hadoop.http.staticuser.user, Vector's message_key) only fail when someone explicitly blanks them.
- Stale or renamed references after edits or upgrades. Config edits and upgrades leave dangling references: a Grav scheduler job captured a backup profile id that no longer exists, a ZeroClaw agent alias was renamed so a dotted provider reference resolves to empty, a Puppet path line was lost during an edit, or a config.yaml regeneration wiped a previously set key like gin-vue-admin's AiPath.
- Hand-built config bypassing the standard loader. Constructing config objects in code or tests instead of going through the normal path skips defaults and validation — wezterm-ssh's "hostname not present in config" only happens when a hand-assembled ConfigMap bypasses Config::for_host(); Chroma's bare Settings() in a custom deployment misses required keys.
What usually fixes it
- [object Object]
- [object Object]
- [object Object]
- [object Object]
- [object Object]
Documented occurrences
- global log_schema.message_key to be valid path (vectordotdev/vector)
- Missing required config value '{key}' (chroma-core/chroma)
- Cannot determine UGI from request or conf (apache/hadoop)
- Database config does not exist! Please read the instructions: https://nginxproxymanager.com/setup/ (NginxProxyManager/nginx-proxy-manager)
- Proxy error: %s or %s set without the other. (apache/hadoop)
- agents.{agent_alias}.model_provider is empty; runtime reload requires a dotted `<type>.<alias>` provider reference (zeroclaw-labs/zeroclaw)
- Missing value for configuration option {} (apache/hadoop)
- Agent has no tts_provider configured. Set `agent.<alias>.tts_provider = "<type>.<alias>"` referencing a [providers.tts.<type>.<alias>] entry. (zeroclaw-labs/zeroclaw)
- Identity format is set to 'aieos' but neither aieos_path nor aieos_inline is configured. Set one in your config: [identity] format = "aieos" aieos_path = "identity.json" Or use inline: [identity] format = "aieos" aieos_inline = '{"identity": {...}}' (zeroclaw-labs/zeroclaw)
- OpenCode native backend requires an instance runtime directory (paperclipai/paperclip)
- No backups defined... (getgrav/grav)
- Provides token '" + key + "' doesn't have any value configured. (apache/maven)
- JetStream cluster requires cluster name (nats-io/nats-server)
- JetStream cluster requires configured routes or solicited leafnode for the system account (nats-io/nats-server)
- No committer defined in mapreduce.outputcommitter.named.classname (apache/hadoop)
- value cannot be blank (apache/hadoop)
- jwt token cannot be validated because verification algorithm is not set (dgraph-io/dgraph)
- no matching node IP for relay (livekit/livekit)
- time_type is :mixed but time_format and time_format_fallbacks is empty. (fluent/fluentd)
- ai:model is required (wavetermdev/waveterm)
…and 78 more across the corpus — use search.
Honest provenance: generated on 2026-09-03 from AI-assisted analysis of the linked records. See how records are made.