windmill-labs/windmill · error
Cannot parse '{s}' as smallint: {e}
Error message
Cannot parse '{s}' as smallint: {e} What it means
convert_val converts a JSON string argument into a tokio-postgres ToSql parameter. When the declared arg type is smallint (smallserial, int2, serial2), it parses the string with i16::from_str; on failure it wraps the ParseIntError into 'Cannot parse ... as smallint'. It exists because the executor takes string params from JSON and must produce a valid INT2 value client-side.
Source
Thrown at backend/windmill-worker/src/pg_executor.rs:1583
|| arg_t == "bigserial"
|| arg_t == "int8"
|| arg_t == "serial8")
&& n.is_u64() =>
{
Ok((Box::new(n.as_u64().unwrap() as i64), Type::INT8))
}
Value::Number(n) if n.is_i64() => Ok((Box::new(n.as_i64().unwrap()), Type::INT8)),
Value::Number(n) => Ok((Box::new(n.as_f64().unwrap()), Type::FLOAT8)),
Value::String(s) if arg_t == "uuid" => Ok((Box::new(Uuid::parse_str(s)?), Type::UUID)),
Value::String(s)
if arg_t == "smallint"
|| arg_t == "smallserial"
|| arg_t == "int2"
|| arg_t == "serial2" =>
{
s.parse::<i16>()
.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())
}View on GitHub (pinned to e474e8803c)
Solutions
- Ensure the input string is a whole number within i16 range (-32768..=32767) before calling the step
- Parse/trim the value in the step script (e.g. Number(str)) and re-submit as a number or validated string
- If the value can exceed 32767, change the column/arg type to int/int4 or bigint/int8
- Pass the value as a JS number instead of a string when the JSON schema allows it, so the numeric arm handles it
Example fix
// before
args: { count: "40000" } // arg_t = smallint -> overflows i16
// after
args: { count: "40000" } // arg_t changed to int, or clamp: Math.min(32767, parseInt(count,10)) Defensive patterns
Strategy: validation
Validate before calling
function assertSmallint(s) {
if (typeof s === "string") {
const n = Number(s);
if (!Number.isInteger(n) || n < -32768 || n > 32767) {
throw new Error(`value ${JSON.stringify(s)} is not a valid smallint (i16)`);
}
}
} Type guard
const isSmallint = (v) => Number.isInteger(Number(v)) && Number(v) >= -32768 && Number(v) <= 32767;
Try / catch
try {
await runPgStep(args);
} catch (e) {
if (String(e.message).includes("as smallint")) {
throw new Error(`Argument must be an integer in [-32768, 32767], got: ${e.message}`);
}
throw e;
} Prevention
- Validate integer inputs and ranges at the form/UI layer
- Reject decimals, thousands separators and empty strings before calling the step
- Use int4/int8 when the range could exceed i16
When it happens
Trigger: A step argument typed smallint/int2 receives a Value::String whose content is not a valid i16 (out of range like '40000', empty string, non-numeric text, or with leading '+ ' or spaces).
Common situations: Form input passed straight through without validation; a value like '32768' exceeding i16 range; user typed '12,5' or '12.5' with a decimal; empty string from an unfilled field; locale-formatted numbers with thousand separators.
Related errors
- Cannot parse '{s}' as integer: {e}
- Cannot parse '{s}' as bigint: {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/3709032382ecc823.
Report an issue: GitHub.