windmill-labs/windmill · error
Cannot parse '{s}' as bigint: {e}
Error message
Cannot parse '{s}' as bigint: {e} What it means
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.
Source
Thrown at backend/windmill-worker/src/pg_executor.rs:1600
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT2))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as smallint: {e}").into())
}
Value::String(s)
if arg_t == "int" || arg_t == "integer" || arg_t == "int4" || arg_t == "serial" =>
{
s.parse::<i32>()
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT4))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as integer: {e}").into())
}
Value::String(s)
if arg_t == "bigint"
|| arg_t == "bigserial"
|| arg_t == "int8"
|| arg_t == "serial8" =>
{
s.parse::<i64>()
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::INT8))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as bigint: {e}").into())
}
Value::String(s) if arg_t == "date" => {
let date = parse_naive_date(s)
.map_err(|e| Error::ExecutionErr(format!("Cannot parse '{s}' as date: {e}")))?;
Ok((Box::new(date), Type::DATE))
}
Value::String(s) if arg_t == "time" => {
let time = parse_naive_time(s)
.map_err(|e| Error::ExecutionErr(format!("Cannot parse '{s}' as time: {e}")))?;
Ok((Box::new(time), Type::TIME))
}
Value::String(s) if arg_t == "timetz" => {
let time = parse_naive_time(s)
.map_err(|e| Error::ExecutionErr(format!("Cannot parse '{s}' as time: {e}")))?;
// See the timetz Null arm — assert TIME, server casts to TIMETZ.
Ok((Box::new(time), Type::TIME))
}
Value::String(s) if arg_t == "timestamp" => {View on GitHub (pinned to e474e8803c)
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
Example fix
// before
args: { snowflake: "1.2345678901234568e+18" } // float corruption -> parse fails
// after
args: { snowflake: "1234567890123456789" } // original string ID, no numeric round-trip Defensive patterns
Strategy: validation
Validate before calling
function assertInt8(s) {
if (typeof s !== "string" || !/^-?\d+$/.test(s.trim())) {
throw new Error(`value ${JSON.stringify(s)} is not a valid bigint literal`);
}
const big = BigInt(s.trim());
if (big < -9223372036854775808n || big > 9223372036854775807n) {
throw new Error("bigint out of i64 range");
}
} Type guard
const isInt8 = (v) => typeof v === "string" && /^-?\d+$/.test(v.trim()) && BigInt(v.trim()) >= -9223372036854775808n && BigInt(v.trim()) <= 9223372036854775807n;
Try / catch
try {
await runPgStep(args);
} catch (e) {
if (String(e.message).includes("as bigint")) {
throw new Error(`Argument must be an i64 integer string, got: ${e.message}`);
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Cannot parse '{s}' as smallint: {e}
- Cannot parse '{s}' as integer: {e}
- Cannot parse '{s}' as numeric: {e}
- Cannot parse '{s}' as real: {e}
- Cannot parse '{s}' as double: {e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/884dac7ecaf8db83.
Report an issue: GitHub.