{"record":{"id":"65e74174d00b3609","repo":"t8y2/dbx","slug":"key-is-required-65e741","errorCode":null,"errorMessage":"{key} is required","messagePattern":"(.+?) is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/tdengine/src/runtime.rs","lineNumber":381,"sourceCode":"        _ => bail!(\"unknown method: {method}\"),\n    }\n}\n\nfn decode<T: DeserializeOwned>(params: &Value) -> Result<T> {\n    serde_json::from_value(params.clone()).with_context(|| \"invalid TDengine agent request parameters\")\n}\n\nfn serialize<T: serde::Serialize>(value: T) -> Result<Value> {\n    serde_json::to_value(value).map_err(anyhow::Error::from)\n}\n\nfn required_string(params: &Value, key: &str) -> Result<String> {\n    params\n        .get(key)\n        .and_then(Value::as_str)\n        .map(str::to_string)\n        .filter(|value| !value.trim().is_empty())\n        .ok_or_else(|| anyhow!(\"{key} is required\"))\n}\n\nfn optional_string(params: &Value, key: &str) -> String {\n    params.get(key).and_then(Value::as_str).unwrap_or_default().to_string()\n}\n\nfn optional_usize(params: &Value, key: &str) -> Option<usize> {\n    params.get(key).and_then(Value::as_u64).and_then(|value| usize::try_from(value).ok())\n}\n\nfn optional_u64(params: &Value, key: &str) -> Option<u64> {\n    params.get(key).and_then(Value::as_u64)\n}\n\nfn string_array(params: &Value, key: &str) -> Result<Vec<String>> {\n    params\n        .get(key)\n        .cloned()","sourceCodeStart":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/tdengine/src/runtime.rs#L363-L399","documentation":"Validation error from `required_string`, a helper that extracts a mandatory string parameter from the JSON `params` object passed to `dispatch`/`dispatch_driver`. It fails when the key is absent, not a string (e.g. a number or null), or present but empty/whitespace-only. The message names the missing key so callers know which field to supply.","triggerScenarios":"Calling dispatch/dispatch_driver without a required key in `params`; passing a JSON null, number, or object where a string is expected; passing `\"\"` or `\"   \"` which the `.filter(|v| !v.trim().is_empty())` rejects.","commonSituations":"Omitting fields like `id` or `sql` in hand-built JSON payloads; forgetting that whitespace-only values are rejected; sending the field with the wrong JSON type (unquoted or numeric); serializing optional fields as null.","solutions":["Add the named key to the params JSON object as a non-empty string.","Check the key spelling against the driver's expected parameter names.","Ensure the value's JSON type is a string, not a number, boolean, or null.","Trim-or-default client-side inputs so empty user input is caught before dispatch."],"exampleFix":"// before\nlet params = json!({\"action\": \"query\"});\n// after\nlet params = json!({\"action\": \"query\", \"sql\": \"SELECT 1\"}); // required key supplied","handlingStrategy":"validation","validationCode":"fn require_param(params: &serde_json::Value, key: &str) -> Result<&str, String> {\n    params.get(key)\n        .and_then(serde_json::Value::as_str)\n        .map(|s| s.trim())\n        .filter(|s| !s.is_empty())\n        .ok_or_else(|| format!(\"{key} is required\"))\n}\n// call before dispatch: require_param(&params, \"sql\")?;","typeGuard":"fn is_nonempty_str(v: &serde_json::Value) -> Option<&str> {\n    v.as_str().filter(|s| !s.trim().is_empty())\n}","tryCatchPattern":null,"preventionTips":["Build params with a typed struct and serde so required fields are compile-time enforced.","Validate all required keys at the call boundary before dispatch.","Never serialize Option fields as null for required params; omit or supply real values.","Add a unit test per dispatch action asserting each required key is present."],"tags":["validation","parameters","rust","json"],"backgroundTag":"missing-required-parameter","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}