{"record":{"id":"caa398afd7433ce6","repo":"bytebase/bytebase","slug":"instance-id-cannot-be-empty","errorCode":null,"errorMessage":"instance ID cannot be empty","messagePattern":"instance ID cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/db/spanner/spanner.go","lineNumber":71,"sourceCode":"\tclient   *spanner.Client\n\tdbClient *spannerdb.DatabaseAdminClient\n\n\t// databaseName is the currently connected database name.\n\tdatabaseName string\n}\n\nfunc newDriver() db.Driver {\n\treturn &Driver{}\n}\n\n// Open opens a Spanner driver. It must connect to a specific database.\n// If database isn't provided, part of the driver cannot function.\nfunc (d *Driver) Open(ctx context.Context, _ storepb.Engine, config db.ConnectionConfig) (db.Driver, error) {\n\tif config.DataSource.ProjectId == \"\" {\n\t\treturn nil, errors.New(\"project ID cannot be empty\")\n\t}\n\tif config.DataSource.InstanceId == \"\" {\n\t\treturn nil, errors.New(\"instance ID cannot be empty\")\n\t}\n\td.config = config\n\td.connCtx = config.ConnectionContext\n\n\tvar o []option.ClientOption\n\tif gcpCredential := config.DataSource.GetGcpCredential(); gcpCredential != nil {\n\t\tcredOption, err := util.GCPCredentialOption([]byte(gcpCredential.Content))\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\to = append(o, credOption)\n\t}\n\t// host and port optionally override the default spanner.googleapis.com:443\n\t// endpoint, e.g. with a Private Service Connect endpoint. gRPC defaults to\n\t// port 443 when no port is given.\n\tif host := config.DataSource.Host; host != \"\" {\n\t\tendpoint := host\n\t\tif port := config.DataSource.Port; port != \"\" {","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/db/spanner/spanner.go#L53-L89","documentation":"Spanner driver Open validation: config.DataSource.InstanceId is empty. A Spanner connection must target one project/instance/database triple; without the instance the database name cannot be formed, so the driver refuses to open.","triggerScenarios":"Calling Open for engine SPANNER where config.DataSource.InstanceId is empty, even if ProjectId is set.","commonSituations":"A data source record that only stores project+database (project/project/databases/db DSN parsed without instance); a config hand-edited or synced from another engine; Spanner instance renamed/deleted so the field was cleared.","solutions":["Set DataSource.InstanceId to the Spanner instance name before opening.","Use the full DSN form projects/<project>/instances/<instance>/databases/<database> so getDatabaseFromDSN-style parsing fills every part.","Verify the stored instance connection config in the metadata DB includes instance ID for Spanner engines."],"exampleFix":"// before\ncfg.DataSource.ProjectId = \"my-gcp-project\"\n// after\ncfg.DataSource.ProjectId = \"my-gcp-project\"\ncfg.DataSource.InstanceId = \"my-instance\"","handlingStrategy":"validation","validationCode":"if cfg.DataSource == nil || cfg.DataSource.InstanceId == \"\" {\n    return errors.New(\"spanner: InstanceId is required\")\n}","typeGuard":null,"tryCatchPattern":"driver, err := d.Open(ctx, engine, cfg)\nif err != nil {\n    if strings.Contains(err.Error(), \"instance ID cannot be empty\") {\n        // prompt user to select a Spanner instance\n    }\n}","preventionTips":["Require instance selection for Spanner connections in the UI.","Re-derive InstanceId from the DSN when it is present there.","Audit stored configs for Spanner engines missing instance ID."],"tags":["spanner","config","gcp"],"backgroundTag":"missing-required-config-field","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}