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

  1. Ensure the input string is a whole number within i16 range (-32768..=32767) before calling the step
  2. Parse/trim the value in the step script (e.g. Number(str)) and re-submit as a number or validated string
  3. If the value can exceed 32767, change the column/arg type to int/int4 or bigint/int8
  4. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/3709032382ecc823. Report an issue: GitHub.