{"id":"323bf9788c1b67f3","repo":"jackc/pgx","slug":"invalid-keyword-value","errorCode":null,"errorMessage":"invalid keyword/value","messagePattern":"invalid keyword/value","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgconn/config.go","lineNumber":727,"sourceCode":"}\n\nfunc isIPOnly(host string) bool {\n\treturn net.ParseIP(strings.Trim(host, \"[]\")) != nil || !strings.Contains(host, \":\")\n}\n\nvar asciiSpace = [256]uint8{'\\t': 1, '\\n': 1, '\\v': 1, '\\f': 1, '\\r': 1, ' ': 1}\n\nfunc parseKeywordValueSettings(s string) (map[string]string, error) {\n\tsettings := make(map[string]string)\n\n\t// Trim any leading whitespace so that the loop exits cleanly when only\n\t// spaces remain (e.g. trailing spaces after the last value).\n\ts = strings.TrimLeft(s, \" \\t\\n\\r\\v\\f\")\n\tfor len(s) > 0 {\n\t\tvar key, val string\n\t\teqIdx := strings.IndexRune(s, '=')\n\t\tif eqIdx < 0 {\n\t\t\treturn nil, errors.New(\"invalid keyword/value\")\n\t\t}\n\n\t\tkey = strings.Trim(s[:eqIdx], \" \\t\\n\\r\\v\\f\")\n\t\ts = strings.TrimLeft(s[eqIdx+1:], \" \\t\\n\\r\\v\\f\")\n\t\tswitch {\n\t\tcase len(s) == 0:\n\t\tcase s[0] != '\\'':\n\t\t\tend := 0\n\t\t\tfor ; end < len(s); end++ {\n\t\t\t\tif asciiSpace[s[end]] == 1 {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif s[end] == '\\\\' {\n\t\t\t\t\tend++\n\t\t\t\t\tif end == len(s) {\n\t\t\t\t\t\treturn nil, errors.New(\"invalid backslash\")\n\t\t\t\t\t}\n\t\t\t\t}","sourceCodeStart":709,"sourceCodeEnd":745,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/config.go#L709-L745","documentation":"Returned by parseKeywordValueSettings when a segment of a keyword/value connection string contains no '=' character. libpq-style conninfo requires key=value pairs separated by whitespace; a missing '=' means the string is not parseable as a pair.","triggerScenarios":"Calling pgx.ParseConfig (or Connect) with a keyword/value string like 'host localhost' (missing '=') or a stray token. The parser finds no '=' before the next key boundary.","commonSituations":"Typos in conninfo strings; copy-pasting a URL-style host without the scheme; trailing tokens after a value; mixing URL and keyword syntax.","solutions":["Rewrite the connection string as key=value pairs: 'host=localhost user=app dbname=db'.","If you meant to use a URL, prefix with 'postgres://': 'postgres://app@localhost/db'.","Validate the conninfo string format before passing it to ParseConfig."],"exampleFix":"// before\ncfg, err := pgx.ParseConfig(\"host localhost user app\")\n\n// after\ncfg, err := pgx.ParseConfig(\"host=localhost user=app\")","handlingStrategy":"validation","validationCode":"// Cheap preflight: every non-quoted token pair must contain '='.\nfunc validateKeywordValue(s string) error {\n    s = strings.TrimSpace(s)\n    for len(s) > 0 {\n        eq := strings.IndexRune(s, '=')\n        if eq < 0 {\n            return fmt.Errorf(\"invalid keyword/value near %q\", s)\n        }\n        // advance past this pair (naive; full parser is in pgx)\n        s = strings.TrimSpace(s[eq+1:])\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := pgx.ParseConfig(connStr); err != nil {\n    if strings.Contains(err.Error(), \"invalid keyword/value\") {\n        return fmt.Errorf(\"connection string is not valid key=value form: %w\", err)\n    }\n}","preventionTips":["Prefer 'postgres://...' URLs which fail with clearer messages.","Construct conninfo from a map[string]string rather than string concatenation.","Unit-test dynamic conninfo builders against pgx.ParseConfig."],"tags":["config","connection-string","parsing"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}