{"record":{"id":"c70dbfbbf45bc6c2","repo":"netdata/netdata","slug":"name-expects-a-string-argument","errorCode":null,"errorMessage":"{name}() expects a string argument","messagePattern":"(.+?)\\(\\) expects a string argument","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/crates/netflow-plugin/src/enrichment/classifiers/parse/value.rs","lineNumber":25,"sourceCode":"    }\n    parse_value_expr(args[0].trim())\n}\n\nfn three_args(name: &str, args: &[String]) -> Result<(ValueExpr, ValueExpr, ValueExpr)> {\n    if args.len() != 3 {\n        anyhow::bail!(\"{name}() expects exactly 3 arguments\");\n    }\n    Ok((\n        parse_value_expr(args[0].trim())?,\n        parse_value_expr(args[1].trim())?,\n        parse_value_expr(args[2].trim())?,\n    ))\n}\n\npub(super) fn one_string_arg(name: &str, args: &[String]) -> Result<ValueExpr> {\n    let value = one_arg(name, args)?;\n    if !value.is_string_expression() {\n        anyhow::bail!(\"{name}() expects a string argument\");\n    }\n    Ok(value)\n}\n\npub(super) fn three_string_args(\n    name: &str,\n    args: &[String],\n) -> Result<(ValueExpr, ValueExpr, ValueExpr)> {\n    let (arg1, arg2, arg3) = three_args(name, args)?;\n    if !arg1.is_string_expression() || !arg2.is_string_expression() || !arg3.is_string_expression()\n    {\n        anyhow::bail!(\"{name}() expects string arguments\");\n    }\n    validate_literal_regex_value(&arg2, name)?;\n    Ok((arg1, arg2, arg3))\n}\n\npub(super) fn validate_literal_regex_value(value: &ValueExpr, context: &str) -> Result<()> {","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/netdata/netdata/blob/4864de85e26f6734d92cfc27ccbeff5921f49938/src/crates/netflow-plugin/src/enrichment/classifiers/parse/value.rs#L7-L43","documentation":"`one_string_arg` verified the argument count (exactly 1 via `one_arg`) but the parsed value expression is not string-typed — `is_string_expression()` returned false. The DSL is typed enough to reject passing a number, field, or list where a string action (SetName, ClassifyRole, ...) requires one.","triggerScenarios":"`SetName(42)`, `ClassifySite(DstPort)`, or any 1-arg string action whose argument parses to a NumberLiteral, numeric Field, or List value expression.","commonSituations":"Passing a numeric literal or numeric flow field to a naming/classification action; assuming implicit number-to-string coercion (the DSL does not coerce).","solutions":["Pass a string-typed expression: a quoted literal, a string flow field, or a Format() call.","Convert numbers explicitly with `Format(\"{}\", DstPort)` if you need them in a string action."],"exampleFix":"// before\nSetName(DstPort)\n\n// after\nSetName(Format(\"port-{}\", DstPort))","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Author-side check: the argument must be a quoted literal, string field, or Format()\nfn is_stringy(term: &str) -> bool {\n    let t = term.trim();\n    t.starts_with('\"') || t.starts_with(\"Format(\") || is_known_string_field(t)\n}\nfn is_known_string_field(f: &str) -> bool {\n    matches!(f, \"SrcIP\" | \"DstIP\" | \"InIfDescription\" | \"OutIfDescription\" | \"ExporterName\")\n}","tryCatchPattern":null,"preventionTips":["String actions need string-typed arguments; numbers and numeric fields are rejected with no coercion.","Wrap numbers with Format(\"{}\", value) when they must feed a string action."],"tags":["rust","classifier","config","parse-error","type-error"],"backgroundTag":null,"analyzedSha":"4864de85e26f6734d92cfc27ccbeff5921f49938","analyzedAt":"2026-08-15T09:12:38.226Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}