windmill-labs/windmill · error
Cannot parse '{s}' as double: {e}
Error message
Cannot parse '{s}' as double: {e} What it means
convert_val converts a JSON string argument into a tokio-postgres ToSql parameter. When the declared arg type is double/double precision/float8, it parses the string with f64::from_str and wraps any ParseFloatError as 'Cannot parse ... as double'. It exists to produce a valid FLOAT8 parameter client-side.
Source
Thrown at backend/windmill-worker/src/pg_executor.rs:1654
// Parse Strings into the matching native Rust type for the remaining
// recognised arg_ts that didn't have a dedicated arm. Without these,
// a string value lands in the generic Value::String fallback below
// (Box<String> + TEXT) and the server-side comparison
// `<numeric|real|...> = text` fails since PG has no implicit cast.
Value::String(s) if arg_t == "numeric" || arg_t == "decimal" => s
.parse::<Decimal>()
.map(|d| (Box::new(d) as Box<dyn ToSql + Sync + Send>, Type::NUMERIC))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as numeric: {e}").into()),
Value::String(s) if arg_t == "real" || arg_t == "float4" => s
.parse::<f32>()
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::FLOAT4))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as real: {e}").into()),
Value::String(s)
if arg_t == "double" || arg_t == "double precision" || arg_t == "float8" =>
{
s.parse::<f64>()
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::FLOAT8))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as double: {e}").into())
}
Value::String(s) if arg_t == "oid" => s
.parse::<u32>()
.map(|n| (Box::new(n) as Box<dyn ToSql + Sync + Send>, Type::OID))
.map_err(|e| anyhow::anyhow!("Cannot parse '{s}' as oid: {e}").into()),
Value::String(s) if arg_t == "bool" || arg_t == "boolean" => {
// Accept the same literals Postgres' boolin() does.
let b = match s.to_ascii_lowercase().as_str() {
"true" | "t" | "yes" | "y" | "1" | "on" => true,
"false" | "f" | "no" | "n" | "0" | "off" => false,
_ => {
return Err(
anyhow::anyhow!("Cannot parse '{s}' as bool: invalid literal").into(),
)
}
};
Ok((Box::new(b), Type::BOOL))
}View on GitHub (pinned to e474e8803c)
Solutions
- Ensure the string is a plain f64-compatible literal before invoking the step
- Strip symbols/units and convert locale decimal commas to dots in the step script
- Reject empty strings earlier in the UI/form validation instead of sending them to the DB step
- Pass as a JSON number where the value round-trips safely
Example fix
// before
args: { ratio: "97.5%" }
// after
args: { ratio: "0.975" } // or strip '%' and divide by 100 before passing Defensive patterns
Strategy: validation
Validate before calling
function assertFloat8(s) {
const raw = typeof s === "string" ? s.trim().replace(",", ".") : s;
const n = Number(raw);
if (Number.isNaN(n) || !Number.isFinite(n)) {
throw new Error(`value ${JSON.stringify(s)} is not a valid float8`);
}
} Type guard
const isFloat8 = (v) => Number.isFinite(Number(typeof v === "string" ? v.trim().replace(",", ".") : v)); Try / catch
try {
await runPgStep(args);
} catch (e) {
if (String(e.message).includes("as double")) {
throw new Error(`Argument must be a finite f64 literal, got: ${e.message}`);
}
throw e;
} Prevention
- Sanitize scraped values (strip %, °, units) before passing
- Validate emptiness at the form layer — empty strings never parse as floats
- Pass JSON numbers where values round-trip safely
When it happens
Trigger: A step argument typed double/float8 receives a Value::String f64::from_str rejects: 'NaN' (Rust f64 parse accepts NaN actually; failures come from '', '1,5', '12%', or arbitrary text), or numbers with units/spaces.
Common situations: Percentages or measurements scraped with symbols ('97.5%'); comma decimal locales; blank inputs from forms; coordinates pasted with degree signs.
Related errors
- Cannot parse '{s}' as real: {e}
- Cannot parse '{s}' as smallint: {e}
- Cannot parse '{s}' as integer: {e}
- Cannot parse '{s}' as bigint: {e}
- Cannot parse '{s}' as numeric: {e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/3dd8537794cb4164.
Report an issue: GitHub.