{"record":{"id":"f06106015135e3bf","repo":"juicedata/juicefs","slug":"update-table-node-s","errorCode":null,"errorMessage":"update table node: %s","messagePattern":"update table node: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/sql.go","lineNumber":772,"sourceCode":"\t\ts := setting{Name: \"format\"}\n\t\tok, err := ses.Get(&s)\n\t\tif err == nil && ok {\n\t\t\tdata = []byte(s.Value)\n\t\t}\n\t\treturn err\n\t})\n\treturn\n}\n\nfunc (m *dbMeta) doNewSession(sinfo []byte, update bool) error {\n\t// add new table\n\terr := m.syncTable(new(session2), new(delslices), new(dirStats), new(detachedNode), new(dirQuota), new(userGroupQuota), new(acl), new(delegationToken), new(changeLog))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"update table session2, delslices, dirstats, detachedNode, dirQuota, userGroupQuota, acl, changeLog: %s\", err)\n\t}\n\t// add node table\n\tif err = m.syncTable(new(node)); err != nil {\n\t\treturn fmt.Errorf(\"update table node: %s\", err)\n\t}\n\t// add primary key\n\tif err = m.syncTable(new(edge), new(chunk), new(xattr), new(sustained)); err != nil {\n\t\treturn fmt.Errorf(\"update table edge, chunk, xattr, sustained: %s\", err)\n\t}\n\t// update the owner from uint64 to int64\n\tif err = m.syncTable(new(flock), new(plock)); err != nil {\n\t\treturn fmt.Errorf(\"update table flock, plock: %s\", err)\n\t}\n\n\tfor {\n\t\tbeans := session2{Sid: m.sid, Expire: m.expireTime(), Info: sinfo}\n\t\tif update {\n\t\t\treturn m.txn(func(s *xorm.Session) error {\n\t\t\t\t_, err = s.Cols(\"expire\", \"info\").Update(&beans, &session2{Sid: beans.Sid})\n\t\t\t\tif err == nil {\n\t\t\t\t\tm.genLog(Background(), s, time.Now().UnixNano(), \"NEWSESSION(%d,%d,%s)\", m.sid, beans.Expire, logEncode(sinfo))\n\t\t\t\t}","sourceCodeStart":754,"sourceCodeEnd":790,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/sql.go#L754-L790","documentation":"During legacy schema upgrade in doNewSession, after syncing added tables, JuiceFS syncs the node table (needed to add the primary key). A syncTable(new(node)) failure is wrapped as 'update table node: %s' and aborts the mount.","triggerScenarios":"Mounting an old-format volume when altering the node table fails — e.g. duplicate rows preventing primary key creation, insufficient ALTER privilege, or lock timeout on a large node table.","commonSituations":"Upgrading a volume with duplicate inode rows in node (prevents adding primary key); RDS account without ALTER; long-running transaction holding metadata locks on node.","solutions":["Check for duplicate Inode rows in the node table and deduplicate before the upgrade (juicefs fsck can help)","Grant ALTER privilege to the metadata user","Kill long-running transactions holding locks on the node table and retry the mount","Back up the metadata before the schema upgrade"],"exampleFix":"-- before\nALTER TABLE jfs_node ADD PRIMARY KEY (inode); -- fails on duplicates\n-- after\n-- dedupe first, e.g. keep min(rowid) per inode, then re-run mount so syncTable adds the primary key","handlingStrategy":"validation","validationCode":"-- Check for duplicate inodes blocking the primary key before upgrading\nSELECT inode, COUNT(*) c FROM node GROUP BY inode HAVING c > 1;","typeGuard":null,"tryCatchPattern":"if err := mount(sqlURL); err != nil {\n    if strings.Contains(err.Error(), \"update table node\") {\n        log.Fatalf(\"dedupe node.inode rows and retry: %v\", err)\n    }\n}","preventionTips":["Run juicefs fsck before major upgrades","Grant ALTER privileges","Avoid lock-heavy concurrent transactions during upgrade"],"tags":["database","sql","schema-upgrade","primary-key"],"backgroundTag":"database-write-failed","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}