{"record":{"id":"e47aaffff367553d","repo":"windmill-labs/windmill","slug":"cannot-convert-default-value-to-json-value-unpa","errorCode":null,"errorMessage":"Cannot convert default value to json\n\tvalue: {unparsed}\n\terror: {e}{}","messagePattern":"Cannot convert default value to json\n\tvalue: (.+?)\n\terror: (.+?)(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/parsers/windmill-parser-ruby/src/lib.rs","lineNumber":143,"sourceCode":"                        if a.kind() == \"identifier\" {\n                            a.utf8_text(code.as_bytes()).inspect(|name| {\n                                args.push(Arg { name: (*name).to_owned(), ..Default::default() })\n                            })?;\n                        }\n                        if a.kind() == \"optional_parameter\" {\n                            let mut walk = a.walk();\n                            let mut it = a.children(&mut walk).into_iter();\n                            match (it.next().and_then(|n| n.utf8_text(code.as_bytes()).ok()), {\n                                // Skip `=`\n                                it.next();\n                                it.next().map(|n| n.range())\n                            }) {\n                                (Some(ident), Some(Range { start_byte, end_byte, .. })) => {\n                                    let unparsed =\n                                        &code[start_byte..end_byte].replace(\"nil\", \"null\");\n                                    let default: Value = serde_json::from_str(unparsed).map_err(\n                                        |e|\n                                        anyhow!(\"Cannot convert default value to json\\n\\tvalue: {unparsed}\\n\\terror: {e}{}\",\n                                            if e.to_string().contains(\"key must be a string\") {\n                                                \"\\n\\nNOTE: If you are trying to declare default hash, use following syntax:\\n { \\\"<key>\\\": <value> }\"\n                                            } else {\n                                                \"\"\n                                            }\n                                        ))?;\n                                    args.push(Arg {\n                                        name: ident.to_owned(),\n                                        typ: json_to_typ(&default, true),\n                                        default: Some(default),\n                                        has_default: true,\n                                        ..Default::default()\n                                    });\n                                }\n                                _ => {\n                                    let Range { start_byte, end_byte, .. } = a.range();\n                                    bail!(\n                                        \"Cannot parse optional parameter: {}\",","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/parsers/windmill-parser-ruby/src/lib.rs#L125-L161","documentation":"`find_main_signature` extracts a Ruby parameter's default value byte-range and coerces it to JSON by naively replacing `nil` with `null` and feeding it to `serde_json::from_str`. Ruby default expressions that are not valid JSON (symbols, method calls, unquoted string literals, Ruby hash syntax with symbol keys) fail, producing \"Cannot convert default value to json\" with the offending value and serde error; if the serde error mentions 'key must be a string', a NOTE about hash syntax is appended.","triggerScenarios":"Declaring a Ruby script main-signature argument whose default is anything but a JSON literal: `def main(a: :sym)`, `def main(x: \"hello\"[unquoted variant])`, `def main(h: { key: 1 })` (Ruby symbol keys), `def main(t: Time.now)`, or string defaults written without JSON-compatible quoting.","commonSituations":"Ruby hash defaults using `{ key: value }` symbol-key syntax instead of JSON `{ \"key\": value }`; boolean/default casing is fine but symbols, interpolated strings, and expressions are not; users porting Ruby defaults from idiomatic Ruby code.","solutions":["Rewrite hash defaults in JSON syntax: `{ \"key\": \"value\" }` (this is exactly what the appended NOTE suggests)","Use only JSON-compatible literals as defaults: numbers, JSON strings (double-quoted), true/false, null, arrays, objects","Replace symbolic or computed defaults with a simple JSON literal, or drop the default and handle absence in code"],"exampleFix":"// before\ndef main(a, h = { key: \"value\" })\n// after\ndef main(a, h = { \"key\": \"value\" })","handlingStrategy":"validation","validationCode":"// # Ruby-side pre-validation of defaults (must be JSON-compatible):\n// def main(a, h = { \"key\": \"value\" })  # JSON-style hash, symbol-free\n// end\n// # quick self-check in Ruby: JSON.parse(default.to_json) rescues nothing to fix","typeGuard":null,"tryCatchPattern":"match signature_result {\n    Ok(m) => m,\n    Err(e) if e.to_string().contains(\"Cannot convert default value to json\") => {\n        // message already embeds the value and a hash-syntax hint; pass through to user\n        Err(e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Use only JSON literals as Ruby main-signature defaults: numbers, \"strings\", true/false, null, [], {}","Write hash defaults with quoted string keys: { \"key\": value }, never { key: value }","Avoid symbols, method calls, and interpolated strings as defaults"],"tags":["ruby","json","serde","default-value"],"backgroundTag":"ruby-default-not-json","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}