{"record":{"id":"299a30ef37e998d5","repo":"quickwit-oss/quickwit","slug":"rest-max-connection-age-grace-requires-rest-max","errorCode":null,"errorMessage":"`rest.max_connection_age_grace` requires `rest.max_connection_age` to be set","messagePattern":"`rest\\.max_connection_age_grace` requires `rest\\.max_connection_age` to be set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-config/src/node_config/serialize.rs","lineNumber":578,"sourceCode":"}\n\nimpl RestConfigBuilder {\n    fn build_and_validate(\n        self,\n        listen_ip: IpAddr,\n        env_vars: &HashMap<String, String>,\n    ) -> anyhow::Result<RestConfig> {\n        let listen_port_from_config_or_default =\n            self.listen_port.unwrap_or(default_rest_listen_port());\n        let listen_port = ConfigValue::<u16, QW_REST_LISTEN_PORT>::with_default(\n            listen_port_from_config_or_default,\n        )\n        .resolve(env_vars)?;\n\n        if let Some(tls_config) = &self.tls_config {\n            tls_config.validate()?;\n        }\n        ensure!(\n            !(self.max_connection_age_grace.is_some() && self.max_connection_age.is_none()),\n            \"`rest.max_connection_age_grace` requires `rest.max_connection_age` to be set\"\n        );\n        let rest_config = RestConfig {\n            listen_addr: SocketAddr::new(listen_ip, listen_port),\n            cors_allow_origins: self.cors_allow_origins,\n            extra_headers: self.extra_headers,\n            tls_config: self.tls_config,\n            max_connection_age: self.max_connection_age,\n            max_connection_age_grace: self.max_connection_age_grace,\n        };\n        Ok(rest_config)\n    }\n}\n\n#[derive(Debug, Deserialize, PartialEq, Default)]\n#[serde(deny_unknown_fields)]\nstruct HealthConfigBuilder {","sourceCodeStart":560,"sourceCodeEnd":596,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-config/src/node_config/serialize.rs#L560-L596","documentation":"The REST server's `max_connection_age_grace` is a grace period applied after `max_connection_age` cuts connections; it is meaningless without a base age. `build_and_validate` rejects a REST config where grace is set but `max_connection_age` is not, ensuring the connection-lifecycle settings stay coherent.","triggerScenarios":"Setting `rest.max_connection_age_grace` (or its env-resolved equivalent) without also setting `rest.max_connection_age` when loading the node config via build_and_validate.","commonSituations":"Operators tune only the grace value copied from a gRPC example; partial config merging drops max_connection_age while keeping grace; typos like nesting grace under a different key so max_connection_age resolves to None.","solutions":["Also set `rest.max_connection_age` alongside `rest.max_connection_age_grace` in the REST config.","Or remove `max_connection_age_grace` if connection aging is not desired.","Verify env vars resolve both keys (a missing max_connection_age env var leaves it None even if YAML looks correct)."],"exampleFix":"// before (quickwit.yaml)\nrest:\n  max_connection_age_grace: 30s\n\n// after (quickwit.yaml)\nrest:\n  max_connection_age: 60s\n  max_connection_age_grace: 30s","handlingStrategy":"validation","validationCode":"if cfg.rest.max_connection_age_grace.is_some() && cfg.rest.max_connection_age.is_none() {\n    return Err(\"rest.max_connection_age_grace set without rest.max_connection_age\");\n}","typeGuard":"fn connection_aging_coherent(rest: &RestConfigDto) -> bool {\n    rest.max_connection_age_grace.is_none() || rest.max_connection_age.is_some()\n}","tryCatchPattern":"match load_node_config(path) {\n    Err(e) if e.to_string().contains(\"max_connection_age_grace\") =>\n        bail!(\"also set rest.max_connection_age (grace requires a base age)\"),\n    other => other,\n}","preventionTips":["Always set max_connection_age and max_connection_age_grace together as a pair.","If only one is needed, set only max_connection_age.","Check env-var overrides resolve both keys consistently."],"tags":["config","validation","rest","grpc"],"backgroundTag":"missing-required-config-field","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}