{"record":{"id":"a67d59e485180003","repo":"risingwavelabs/risingwave","slug":"unrecognized-format-type-specifier-0","errorCode":null,"errorMessage":"unrecognized format() type specifier \"{0}\"","messagePattern":"unrecognized format\\(\\) type specifier \"(.+?)\"","errorType":"error_code","errorClass":"ParseFormatError","httpStatus":null,"severity":"error","filePath":"src/expr/impl/src/scalar/format.rs","lineNumber":121,"sourceCode":"struct Specifier {\n    // TODO: support position, flags and width.\n    ty: SpecifierType,\n}\n\n#[derive(Debug)]\nenum FormatterNode {\n    Specifier(Specifier),\n    Literal(String),\n}\n\n#[derive(Debug)]\nstruct Formatter {\n    nodes: Vec<FormatterNode>,\n}\n\n#[derive(Debug, thiserror::Error)]\nenum ParseFormatError {\n    #[error(\"unrecognized format() type specifier \\\"{0}\\\"\")]\n    UnrecognizedSpecifierType(char),\n    #[error(\"unterminated format() type specifier\")]\n    UnterminatedSpecifier,\n}\n\nimpl FromStr for Formatter {\n    type Err = ParseFormatError;\n\n    /// Parse the format string into a high-efficient representation.\n    /// <https://www.postgresql.org/docs/current/functions-string.html#FUNCTIONS-STRING-FORMAT>\n    fn from_str(format: &str) -> std::result::Result<Self, ParseFormatError> {\n        // 8 is a good magic number here, it can cover an input like 'Testing %s, %s, %s, %%'.\n        let mut nodes = Vec::with_capacity(8);\n        let mut after_percent = false;\n        let mut literal = String::with_capacity(8);\n        for c in format.chars() {\n            if after_percent && c == '%' {\n                literal.push('%');","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/impl/src/scalar/format.rs#L103-L139","documentation":"The format() function's format-string parser (ParseFormatError::UnrecognizedSpecifierType) fails when it encounters a type specifier character it does not recognize inside %(...) patterns. Only a fixed set of specifier types (e.g. s, i/d, f and similar) is accepted; anything else is rejected with the offending char in the message.","triggerScenarios":"Calling `SELECT format(...)` with a format string containing a specifier type character outside the supported set, e.g. `format('%(x)q', ...)` — the parser reads 'q' and returns UnrecognizedSpecifierType('q').","commonSituations":"Porting format strings from C printf or Python %-formatting that use unsupported conversion characters; typos in specifier letters; literals containing % followed by parentheses intended as plain text without escaping.","solutions":["Replace the unsupported specifier with a supported one (s for string, d/i for integer, f for float, etc.).","Escape or rephrase literal % sequences in the format string so they aren't parsed as specifiers.","Consult the format() documentation for the exact list of accepted type specifier characters."],"exampleFix":"// before\nSELECT format('%(a)d and %(b)x', a := 1, b := 255);\n// after\nSELECT format('%(a)d and %(b)s', a := 1, b := to_hex(255));","handlingStrategy":"validation","validationCode":"const SUPPORTED: &str = \"sdif\"; // per format() docs\nfn check_specifiers(fmt: &str) -> Result<(), char> {\n    let bytes: Vec<char> = fmt.chars().collect();\n    for i in 0..bytes.len() {\n        if bytes[i] == '%' && i + 1 < bytes.len() && bytes[i+1] == '(' {\n            if let Some(close) = bytes[i+2..].iter().position(|&c| c == ')') {\n                let spec = bytes[i + 3 + close];\n                if !SUPPORTED.contains(spec) { return Err(spec); }\n            }\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"let formatted = sqlx::query_scalar::<_, String>(\"SELECT format($1, $2)\")\n    .bind(fmt).bind(args)\n    .await\n    .map_err(|e| if e.to_string().contains(\"unrecognized format() type specifier\") {\n        FormatStringError(e.to_string())\n    } else { e.into() })?;","preventionTips":["Use only documented specifier characters (s, d/i, f, etc.) in format strings.","Escape literal % sequences intended as plain text.","Unit-test format strings extracted from config/templates."],"tags":["format","parsing","sql"],"backgroundTag":"invalid-argument-format","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}