{"record":{"id":"884dac7ecaf8db83","repo":"windmill-labs/windmill","slug":"cannot-parse-s-as-bigint-e","errorCode":null,"errorMessage":"Cannot parse '{s}' as bigint: {e}","messagePattern":"Cannot parse '(.+?)' as bigint: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/pg_executor.rs","lineNumber":1600,"sourceCode":"                .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)\n                .map_err(|e| Error::ExecutionErr(format!(\"Cannot parse '{s}' as time: {e}\")))?;\n            Ok((Box::new(time), Type::TIME))\n        }\n        Value::String(s) if arg_t == \"timetz\" => {\n            let time = parse_naive_time(s)\n                .map_err(|e| Error::ExecutionErr(format!(\"Cannot parse '{s}' as time: {e}\")))?;\n            // See the timetz Null arm — assert TIME, server casts to TIMETZ.\n            Ok((Box::new(time), Type::TIME))\n        }\n        Value::String(s) if arg_t == \"timestamp\" => {","sourceCodeStart":1582,"sourceCodeEnd":1618,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/pg_executor.rs#L1582-L1618","documentation":"convert_val converts a JSON string argument into a tokio-postgres ToSql parameter. When the declared arg type is bigint/bigserial/int8/serial8, it parses the string with i64::from_str and wraps any ParseIntError as 'Cannot parse ... as bigint'. It exists to guarantee a valid INT8 parameter is produced before the query runs.","triggerScenarios":"A step argument typed bigint/int8 receives a Value::String that is not a valid i64 (e.g. a 64-bit snowflake ID quoted with decimals, scientific notation like '1e18', an empty string, or an ID exceeding 9223372036854775807).","commonSituations":"JS clients stringifying a Number that already lost precision then adding formatting; IDs from other systems (Discord/Twitter snowflakes) pasted as strings with whitespace; values read as floats from CSV so '12345678901234567890.0' arrives.","solutions":["Validate the string is a whole number within i64 range before invoking the step","Keep true 64-bit IDs as strings end-to-end and strip any formatting/whitespace before passing","If the number legitimately exceeds i64, store it as numeric instead of bigint","Check upstream producers (JS Number) are not corrupting precision; use BigInt or string-safe serialization"],"exampleFix":"// before\nargs: { snowflake: \"1.2345678901234568e+18\" }  // float corruption -> parse fails\n// after\nargs: { snowflake: \"1234567890123456789\" }  // original string ID, no numeric round-trip","handlingStrategy":"validation","validationCode":"function assertInt8(s) {\n  if (typeof s !== \"string\" || !/^-?\\d+$/.test(s.trim())) {\n    throw new Error(`value ${JSON.stringify(s)} is not a valid bigint literal`);\n  }\n  const big = BigInt(s.trim());\n  if (big < -9223372036854775808n || big > 9223372036854775807n) {\n    throw new Error(\"bigint out of i64 range\");\n  }\n}","typeGuard":"const isInt8 = (v) => typeof v === \"string\" && /^-?\\d+$/.test(v.trim()) && BigInt(v.trim()) >= -9223372036854775808n && BigInt(v.trim()) <= 9223372036854775807n;","tryCatchPattern":"try {\n  await runPgStep(args);\n} catch (e) {\n  if (String(e.message).includes(\"as bigint\")) {\n    throw new Error(`Argument must be an i64 integer string, got: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Never round-trip 64-bit IDs through JS Number — keep them as strings end-to-end","Validate with a strict integer regex (no exponent, no decimals) before passing","Use numeric columns for values beyond i64"],"tags":["postgresql","parse-error","bigint","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"}