{"record":{"id":"20ce612def523deb","repo":"multica-ai/multica","slug":"empty-identifier","errorCode":null,"errorMessage":"empty identifier","messagePattern":"empty identifier","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/cmd/migrate/main.go","lineNumber":471,"sourceCode":"\t\tfmt.Printf(\"  %s  %s\\n\", opts.Direction, version)\n\t}\n\n\treturn nil\n}\n\n// quoteQualifiedIdentifier safely quotes either an unqualified table\n// name (\"foo\") or a schema-qualified name (\"schema.foo\") for embedding\n// into a SQL statement. Postgres does not let parametrized queries\n// supply identifiers, so we have to interpolate, but pgx.Identifier\n// does the right escaping (double-quotes, embedded-quote handling).\n//\n// The accepted shape is exactly one or two dot-separated components.\n// Names containing more than one dot are rejected outright rather than\n// silently sanitized into a \"schema\".\"b.c\" reference, which is valid\n// SQL but almost certainly not what the caller meant.\nfunc quoteQualifiedIdentifier(name string) (string, error) {\n\tif name == \"\" {\n\t\treturn \"\", fmt.Errorf(\"empty identifier\")\n\t}\n\tparts := strings.Split(name, \".\")\n\tif len(parts) > 2 {\n\t\treturn \"\", fmt.Errorf(\"identifier %q has more than one dot; only schema.table is supported\", name)\n\t}\n\tfor _, p := range parts {\n\t\tif p == \"\" {\n\t\t\treturn \"\", fmt.Errorf(\"empty component in %q\", name)\n\t\t}\n\t}\n\treturn pgx.Identifier(parts).Sanitize(), nil\n}\n","sourceCodeStart":453,"sourceCodeEnd":484,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/cmd/migrate/main.go#L453-L484","documentation":"quoteQualifiedIdentifier rejects an empty string before building a quoted SQL identifier. Because Postgres cannot take identifiers as query parameters, the function interpolates them via pgx.Identifier.Sanitize, and an empty name would otherwise interpolate to an empty (invalid) reference.","triggerScenarios":"Calling quoteQualifiedIdentifier(\"\") — typically because a table name came from a flag, env var, or config value that was never set or was trimmed to empty.","commonSituations":"A CLI flag like --table left blank; a config key read with a default of \"\"; a loop over a list where one element is an empty string after splitting on a delimiter.","solutions":["Trace where the name originates (flag/config) and require it explicitly before calling.","Add a non-empty default or fail fast at flag-parsing time with an actionable message.","Sanitize lists by filtering out empty elements before iterating."],"exampleFix":"// before\nq, err := quoteQualifiedIdentifier(tableName)\n\n// after\nif strings.TrimSpace(tableName) == \"\" {\n    return fmt.Errorf(\"--table is required\")\n}\nq, err := quoteQualifiedIdentifier(strings.TrimSpace(tableName))","handlingStrategy":"validation","validationCode":"func safeIdentifier(name string) (string, error) {\n    name = strings.TrimSpace(name)\n    if name == \"\" {\n        return \"\", fmt.Errorf(\"table name is required\")\n    }\n    return quoteQualifiedIdentifier(name)\n}","typeGuard":"func isValidIdentifierName(name string) bool {\n    if name == \"\" {\n        return false\n    }\n    for _, p := range strings.Split(name, \".\") {\n        if p == \"\" {\n            return false\n        }\n    }\n    return len(strings.Split(name, \".\")) <= 2\n}","tryCatchPattern":"q, err := quoteQualifiedIdentifier(name)\nif err != nil {\n    return fmt.Errorf(\"invalid table %q from config: %w\", name, err)\n}","preventionTips":["Validate non-empty at flag/config parse time with a message naming the flag or key.","Filter empty elements when building identifier lists from splits/joins.","Never pass user input straight through; route everything through quoteQualifiedIdentifier."],"tags":["go","validation","sql","identifiers"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}