{"record":{"id":"2adc3e16b3681fc3","repo":"windmill-labs/windmill","slug":"cannot-parse-s-as-integer-e","errorCode":null,"errorMessage":"Cannot parse '{s}' as integer: {e}","messagePattern":"Cannot parse '(.+?)' as integer: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/pg_executor.rs","lineNumber":1590,"sourceCode":"        Value::Number(n) if n.is_i64() => Ok((Box::new(n.as_i64().unwrap()), Type::INT8)),\n        Value::Number(n) => Ok((Box::new(n.as_f64().unwrap()), Type::FLOAT8)),\n        Value::String(s) if arg_t == \"uuid\" => Ok((Box::new(Uuid::parse_str(s)?), Type::UUID)),\n        Value::String(s)\n            if arg_t == \"smallint\"\n                || arg_t == \"smallserial\"\n                || arg_t == \"int2\"\n                || arg_t == \"serial2\" =>\n        {\n            s.parse::<i16>()\n                .map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT2))\n                .map_err(|e| anyhow::anyhow!(\"Cannot parse '{s}' as smallint: {e}\").into())\n        }\n        Value::String(s)\n            if arg_t == \"int\" || arg_t == \"integer\" || arg_t == \"int4\" || arg_t == \"serial\" =>\n        {\n            s.parse::<i32>()\n                .map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT4))\n                .map_err(|e| anyhow::anyhow!(\"Cannot parse '{s}' as integer: {e}\").into())\n        }\n        Value::String(s)\n            if arg_t == \"bigint\"\n                || arg_t == \"bigserial\"\n                || arg_t == \"int8\"\n                || arg_t == \"serial8\" =>\n        {\n            s.parse::<i64>()\n                .map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT8))\n                .map_err(|e| anyhow::anyhow!(\"Cannot parse '{s}' as bigint: {e}\").into())\n        }\n        Value::String(s) if arg_t == \"date\" => {\n            let date = parse_naive_date(s)\n                .map_err(|e| Error::ExecutionErr(format!(\"Cannot parse '{s}' as date: {e}\")))?;\n            Ok((Box::new(date), Type::DATE))\n        }\n        Value::String(s) if arg_t == \"time\" => {\n            let time = parse_naive_time(s)","sourceCodeStart":1572,"sourceCodeEnd":1608,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/pg_executor.rs#L1572-L1608","documentation":"convert_val converts a JSON string argument into a tokio-postgres ToSql parameter. When the declared arg type is int/integer/int4/serial, it parses the string with i32::from_str and wraps any ParseIntError as 'Cannot parse ... as integer'. It exists because string params coming from JSON must be turned into a valid INT4 client-side.","triggerScenarios":"A step argument typed int/integer/int4/serial receives a Value::String that is not a valid i32 (e.g. '2147483648', '', 'abc', '3.14', or ' 42' with whitespace).","commonSituations":"Numbers copied from Excel with formatting; values above 2^31-1 that need bigint; decimal inputs; empty or whitespace-only form fields; IDs pasted with trailing characters.","solutions":["Validate the string is a whole number within i32 range (-2147483648..=2147483647) before invoking the step","Trim/normalize the input and remove decimal or thousands separators before passing","If values exceed i32 range, change the arg/column type to bigint/int8","Pass as a JSON number instead of a string so it follows the numeric conversion path"],"exampleFix":"// before\nargs: { user_id: \"42 \" }  // trailing space -> ParseIntError\n// after\nargs: { user_id: user_id.trim() }  // or Number(user_id) validated as integer","handlingStrategy":"validation","validationCode":"function assertInt4(s) {\n  const n = Number(typeof s === \"string\" ? s.trim() : s);\n  if (!Number.isInteger(n) || n < -2147483648 || n > 2147483647) {\n    throw new Error(`value ${JSON.stringify(s)} is not a valid integer (i32)`);\n  }\n}","typeGuard":"const isInt4 = (v) => Number.isInteger(Number(typeof v === \"string\" ? v.trim() : v)) && Number(v) >= -2147483648 && Number(v) <= 2147483647;","tryCatchPattern":"try {\n  await runPgStep(args);\n} catch (e) {\n  if (String(e.message).includes(\"as integer\")) {\n    throw new Error(`Argument must be an i32 integer, got: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Trim and normalize numeric strings before passing them","Route values above 2^31-1 to bigint args instead","Validate with Number.isInteger before invoking the step"],"tags":["postgresql","parse-error","integer","type-conversion"],"backgroundTag":"invalid-number-format","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}