{"record":{"id":"34aa2818a1523d1f","repo":"jmoiron/sqlx","slug":"unexpected-while-reading-named-param-at","errorCode":null,"errorMessage":"unexpected `:` while reading named param at ","messagePattern":"unexpected `:` while reading named param at ","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"named.go","lineNumber":349,"sourceCode":"func compileNamedQuery(qs []byte, bindType int) (query string, names []string, err error) {\n\tnames = make([]string, 0, 10)\n\trebound := make([]byte, 0, len(qs))\n\n\tinName := false\n\tlast := len(qs) - 1\n\tcurrentVar := 1\n\tname := make([]byte, 0, 10)\n\n\tfor i, b := range qs {\n\t\t// a ':' while we're in a name is an error\n\t\tif b == ':' {\n\t\t\t// if this is the second ':' in a '::' escape sequence, append a ':'\n\t\t\tif inName && i > 0 && qs[i-1] == ':' {\n\t\t\t\trebound = append(rebound, ':')\n\t\t\t\tinName = false\n\t\t\t\tcontinue\n\t\t\t} else if inName {\n\t\t\t\terr = errors.New(\"unexpected `:` while reading named param at \" + strconv.Itoa(i))\n\t\t\t\treturn query, names, err\n\t\t\t}\n\t\t\tinName = true\n\t\t\tname = []byte{}\n\t\t} else if inName && i > 0 && b == '=' && len(name) == 0 {\n\t\t\trebound = append(rebound, ':', '=')\n\t\t\tinName = false\n\t\t\tcontinue\n\t\t\t// if we're in a name, and this is an allowed character, continue\n\t\t} else if inName && (unicode.IsOneOf(allowedBindRunes, rune(b)) || b == '_' || b == '.') && i != last {\n\t\t\t// append the byte to the name if we are in a name and not on the last byte\n\t\t\tname = append(name, b)\n\t\t\t// if we're in a name and it's not an allowed character, the name is done\n\t\t} else if inName {\n\t\t\tinName = false\n\t\t\t// if this is the final byte of the string and it is part of the name, then\n\t\t\t// make sure to add it to the name\n\t\t\tif i == last && unicode.IsOneOf(allowedBindRunes, rune(b)) {","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/jmoiron/sqlx/blob/41dac167fdad5e3fd81d66cafba0951dc6823a30/named.go#L331-L367","documentation":"When compiling a named query, sqlx treats ':' as the start of a named parameter (:name). A second ':' encountered while still inside a parameter name is only legal as the PostgreSQL cast escape '::'. Any other unexpected ':' inside a name (e.g. '::' logic confusion or ':a:b') means the named syntax is malformed, so compilation fails with this error including the byte offset.","triggerScenarios":"Calling NamedQuery/PrepareNamed/Get/Select with a query containing malformed named params like \":a:b\", or a lone ':' immediately after an incomplete name, where compileNamedQuery's inName state meets another ':' that isn't part of '::'.","commonSituations":"Mixing PostgreSQL casts (::type) with named params and mis-escaping; accidentally writing two adjacent named params without text between them; porting queries from other libraries with different placeholder syntaxes.","solutions":["Fix the query so each ':' begins a valid name followed by alphanumerics and ends cleanly","Escape a literal '::' cast properly (sqlx handles '::' — ensure there is no stray single ':' before it)","Rename params so none contain ':' inside the name (e.g. :from_date not :from:date)","Use '?' positional binding with sqlx.In if the query needs complex placeholder syntax"],"exampleFix":"// before\nq := \"SELECT * FROM t WHERE created::date = :day AND ts:::tz IS NULL\"\n// after\nq := \"SELECT * FROM t WHERE created::date = :day AND ts::timestamptz IS NULL\"","handlingStrategy":"validation","validationCode":"func validateNamedParams(query string) error {\n    for i := 0; i < len(query); i++ {\n        if query[i] == ':' {\n            if i+1 < len(query) && query[i+1] == ':' { i++; continue } // :: cast\n            j := i + 1\n            for j < len(query) && (query[j] == '_' || isAlnum(query[j])) { j++ }\n            if j == i+1 { return fmt.Errorf(\"empty named param at %d\", i) }\n            if j < len(query) && query[j] == ':' { return fmt.Errorf(\"unexpected ':' after param at %d\", j) }\n            i = j - 1\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"query, args, err := db.PrepareNamed(q)\nif err != nil {\n    if strings.Contains(err.Error(), \"unexpected `:`\") {\n        log.Printf(\"malformed named param near offset in %s\", q)\n    }\n    return err\n}","preventionTips":["Only use :: escapes for PostgreSQL casts; avoid other double-colon sequences","Never embed ':' inside parameter names","Lint queries for stray ':' characters before runtime"],"tags":["go","sqlx","named-parameters","query-parsing"],"backgroundTag":"malformed-named-parameter","analyzedSha":"41dac167fdad5e3fd81d66cafba0951dc6823a30","analyzedAt":"2026-09-03T06:10:20.382Z","contentChangedAt":"2026-09-03T06:10:20.382Z","schemaVersion":2},"datasetVersion":"2026-09-10T12:17:11.382Z"}