windmill-labs/windmill · error
Invalid S3 mode argument: {}
Error message
Invalid S3 mode argument: {} What it means
In S3 mode, a SQL script's return/parameter type carries inline options as a space-separated list of `key=value` pairs (e.g. `s3:// prefix=foo storage=r2 format=parquet`). `parse_s3_mode` splits that string and raises this error when any token lacks an `=` separator, i.e. it is not a valid `key=value` argument.
Source
Thrown at backend/parsers/windmill-parser-sql/src/lib.rs:180
Some(x) => x,
None => return Ok(None),
};
let args_str = cap
.get(1)
.map(|x| x.as_str().to_string())
.unwrap_or_default();
let mut prefix = None;
let mut storage = None;
let mut format = S3ModeFormat::Json;
for kv in args_str.split(' ').map(|kv| kv.trim()) {
if kv.is_empty() {
continue;
}
let mut it = kv.split('=');
let (Some(key), Some(value)) = (it.next(), it.next()) else {
return Err(anyhow!("Invalid S3 mode argument: {}", kv));
};
match (key.trim(), value.trim()) {
("prefix", _) => prefix = Some(value.to_string()),
("storage", _) => storage = Some(value.to_string()),
("format", "json") => format = S3ModeFormat::Json,
("format", "parquet") => format = S3ModeFormat::Parquet,
("format", "csv") => format = S3ModeFormat::Csv,
("format", format) => return Err(anyhow!("Invalid S3 mode format: {}", format)),
(_, _) => return Err(anyhow!("Invalid S3 mode argument: {}", kv)),
}
}
Ok(Some(S3ModeArgs { prefix, storage, format }))
}
pub fn parse_sql_blocks(code: &str, track_dollar_quotes: bool) -> Vec<&str> {
let mut blocks = vec![];
let mut last_idx = 0;View on GitHub (pinned to e474e8803c)
Solutions
- Rewrite the s3-mode options as `key=value` pairs separated by single spaces: `prefix=x storage=y format=parquet`.
- Check the full message — the offending token is printed after the colon — and add the missing `=` or value.
- Ensure values don't contain unescaped spaces; avoid spaces in prefixes/storage names.
- Keep `format` limited to `json` or `parquet` (other keys/values have their own validation).
Example fix
// before s3:// prefix format // after s3:// prefix=my-folder format=parquet
Defensive patterns
Strategy: validation
Validate before calling
// Rust: validate s3-mode options are all key=value before calling the parser
fn valid_s3_mode_opts(opts: &str) -> bool {
opts.split(' ')
.map(str::trim)
.filter(|kv| !kv.is_empty())
.all(|kv| kv.split_once('=').map_or(false, |(k, v)| !k.is_empty() && !v.is_empty()))
} Try / catch
// Rust
match parse_s3_mode(args_str) {
Ok(mode) => mode,
Err(e) if e.to_string().contains("Invalid S3 mode argument") => {
eprintln!("{e} — expected key=value pairs like 'prefix=x format=parquet'");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Always write s3 options as `key=value` pairs separated by single spaces.
- Never include bare tokens or `key:` style separators in the s3 extension string.
- Avoid spaces inside values (prefix/storage names) so splitting is unambiguous.
- Keep `format` restricted to `json` or `parquet`.
When it happens
Trigger: Calling `parse_s3_mode` (from `do_postgresql`, `do_mysql`, `do_bigquery`, `do_mssql`, `do_snowflake`, `do_oracledb` when the s3-mode extension is present) with an s3-mode argument string containing a bare token with no `=`, such as `s3:// prefix` or `format` without a value.
Common situations: Hand-editing the s3 type extension and dropping the `=` or the value (`format` instead of `format=parquet`); using spaces inside a value without quoting so it splits into bare tokens; typos like `prefix:foo`; copying an s3 mode string from docs with truncated options.
Related errors
- Error parsing sql
- result.substring(__RESULT_ERR_PREFIX.length)
- Error parsing yaml ${path}
- Unimplemented case
- Unsupported database type: ${dbType}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/2652feb3d32175bf.
Report an issue: GitHub.