{"record":{"id":"642d56b51ee39449","repo":"bytebase/bytebase","slug":"failed-to-get-keys","errorCode":null,"errorMessage":"failed to get keys","messagePattern":"failed to get keys","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/plugin/db/mssql/sync.go","lineNumber":1423,"sourceCode":"\t\t}\n\t\tslices.SortFunc(tableIndexes[k], func(a, b *storepb.IndexMetadata) int {\n\t\t\tif a.Name < b.Name {\n\t\t\t\treturn -1\n\t\t\t}\n\t\t\tif a.Name > b.Name {\n\t\t\t\treturn 1\n\t\t\t}\n\t\t\treturn 0\n\t\t})\n\t}\n\treturn tableIndexes, nil\n}\n\n// getIndexes gets all indices of a database.\nfunc getKeyAndIndexes(txn *sql.Tx, schemas []string) (map[db.TableKey][]*storepb.IndexMetadata, error) {\n\tkeys, err := getKeys(txn, schemas)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to get keys\")\n\t}\n\tindexes, err := getIndexes(txn, schemas)\n\tif err != nil {\n\t\treturn nil, errors.Wrapf(err, \"failed to get indexes\")\n\t}\n\tfor k, v := range indexes {\n\t\tkeys[k] = append(keys[k], v...)\n\t}\n\treturn keys, nil\n}\n\n// getViews gets all views of a database.\nfunc getViews(txn *sql.Tx, columnMap map[db.TableKey][]*storepb.ColumnMetadata) (map[string][]*storepb.ViewMetadata, error) {\n\tviewMap := make(map[string][]*storepb.ViewMetadata)\n\n\t// Get view comments separately\n\tviewCommentsMap := make(map[int]string)\n\tcommentsQuery := `","sourceCodeStart":1405,"sourceCodeEnd":1441,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/plugin/db/mssql/sync.go#L1405-L1441","documentation":"Wraps an error returned by getKeys while getKeyAndIndexes assembles the full index/key metadata map for a MSSQL database. getKeys reads key/PK/unique index rows from catalog views; the failure means that query or its iteration failed.","triggerScenarios":"Calling syncDatabases (MSSQL) when the getKeys catalog query against sys.indexes/sys.key_constraints fails or its row iteration errors.","commonSituations":"Permission-restricted sync logins; huge catalogs timing out; deadlocks with concurrent schema changes; broken connections during sync.","solutions":["Unwrap the inner error to identify the failing catalog query, then fix that root cause.","Grant VIEW DEFINITION and catalog view access to the sync login.","Retry on transient errors (deadlock/timeout); reduce scope by syncing specific schemas."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// confirm the sync login can read key metadata before calling sync\nconst probe = \"SELECT TOP 1 1 FROM sys.key_constraints\"\nif _, err := txn.Query(probe); err != nil {\n    return fmt.Errorf(\"insufficient catalog permissions for getKeys: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"keys, err := getKeys(txn, schemas)\nif err != nil {\n    return nil, fmt.Errorf(\"failed to get keys: %w — check permissions on sys.key_constraints and retry\", err)\n}","preventionTips":["Grant VIEW DEFINITION and catalog read access to the sync login.","Scope syncs to specific schemas to keep result sets small.","Add retries for transient deadlock/timeout error codes (1205, -2 timeout)."],"tags":["mssql","schema-sync","index-metadata"],"backgroundTag":"database-query-failed","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"}