{"record":{"id":"b3577ba08412b122","repo":"golang-migrate/migrate","slug":"x-migrations-table-must-be-quoted-for-instance-b3577b","errorCode":null,"errorMessage":"x-migrations-table must be quoted (for instance '\"migrate\".\"schema_migrations\"') when x-migrations-table-quoted is enabled, current value is: %s","messagePattern":"x-migrations-table must be quoted \\(for instance '\"migrate\"\\.\"schema_migrations\"'\\) when x-migrations-table-quoted is enabled, current value is: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"database/pgx/v5/pgx.go","lineNumber":164,"sourceCode":"\t// when making actual connection\n\t// i.e. pgx://user:password@host:port/db => postgres://user:password@host:port/db\n\tpurl.Scheme = \"postgres\"\n\n\tdb, err := sql.Open(\"pgx/v5\", migrate.FilterCustomQuery(purl).String())\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tmigrationsTable := purl.Query().Get(\"x-migrations-table\")\n\tmigrationsTableQuoted := false\n\tif s := purl.Query().Get(\"x-migrations-table-quoted\"); len(s) > 0 {\n\t\tmigrationsTableQuoted, err = strconv.ParseBool(s)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse option x-migrations-table-quoted: %w\", err)\n\t\t}\n\t}\n\tif (len(migrationsTable) > 0) && (migrationsTableQuoted) && ((migrationsTable[0] != '\"') || (migrationsTable[len(migrationsTable)-1] != '\"')) {\n\t\treturn nil, fmt.Errorf(\"x-migrations-table must be quoted (for instance '\\\"migrate\\\".\\\"schema_migrations\\\"') when x-migrations-table-quoted is enabled, current value is: %s\", migrationsTable)\n\t}\n\n\tstatementTimeoutString := purl.Query().Get(\"x-statement-timeout\")\n\tstatementTimeout := 0\n\tif statementTimeoutString != \"\" {\n\t\tstatementTimeout, err = strconv.Atoi(statementTimeoutString)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tmultiStatementMaxSize := DefaultMultiStatementMaxSize\n\tif s := purl.Query().Get(\"x-multi-statement-max-size\"); len(s) > 0 {\n\t\tmultiStatementMaxSize, err = strconv.Atoi(s)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tif multiStatementMaxSize <= 0 {","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/database/pgx/v5/pgx.go#L146-L182","documentation":"golang-migrate requires that when x-migrations-table-quoted=true, the x-migrations-table value must be a fully double-quoted Postgres identifier (starting and ending with \"), e.g. \"migrate\".\"schema_migrations\". If a migrations table is set but the first or last character is not a quote, Open rejects the URL. This guards against accidentally treating an unquoted identifier as a quoted one.","triggerScenarios":"Open with a URL containing both x-migrations-table=schema_migrations and x-migrations-table-quoted=true, where the table value does not start and end with '\"', e.g. ?x-migrations-table=migrate.schema_migrations&x-migrations-table-quoted=true.","commonSituations":"Enabling the quoted flag but forgetting to wrap the table (and optional schema) in double quotes; JSON/YAML/shell layers stripping the quote characters; copy-pasting a plain table name while adding the new quoted option after upgrading golang-migrate.","solutions":["Wrap the migrations table value in double quotes, including the schema if present: x-migrations-table=\"migrate\".\"schema_migrations\"","Ensure quotes survive URL encoding/shell quoting — use single-quoted shell strings or percent-encode (%22)","Set x-migrations-table-quoted=false if the table name does not need case-sensitivity or special characters","Drop x-migrations-table-quoted entirely when using a plain unquoted table name"],"exampleFix":"// before\ndsn := \"postgres://u:p@host/db?x-migrations-table=migrate.schema_migrations&x-migrations-table-quoted=true\"\n// after\ndsn := `postgres://u:p@host/db?x-migrations-table=\"migrate\".\"schema_migrations\"&x-migrations-table-quoted=true`","handlingStrategy":"validation","validationCode":"u, _ := url.Parse(dsn)\nq := u.Query()\ntbl := q.Get(\"x-migrations-table\")\nif q.Get(\"x-migrations-table-quoted\") == \"true\" && tbl != \"\" {\n    if !strings.HasPrefix(tbl, `\"`) || !strings.HasSuffix(tbl, `\"`) {\n        return fmt.Errorf(\"x-migrations-table must be fully quoted, got %q\", tbl)\n    }\n}","typeGuard":"func isFullyQuotedIdentifier(s string) bool {\n    return len(s) >= 2 && strings.HasPrefix(s, `\"`) && strings.HasSuffix(s, `\"`)\n}","tryCatchPattern":"if err := migrateOpen(); err != nil {\n    if strings.Contains(err.Error(), \"x-migrations-table must be quoted\") {\n        log.Fatalf(\"wrap x-migrations-table in double quotes: %v\", err)\n    }\n    panic(err)\n}","preventionTips":["When enabling x-migrations-table-quoted, always write the table as \"schema\".\"table\"","Single-quote shell strings containing double quotes to prevent stripping","Prefer setting MigrationsTable in a Go raw string literal (`...`) over interpolated DSNs"],"tags":["configuration","url-parameters","postgres","identifier-quoting"],"backgroundTag":"invalid-identifier-quoting","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}