{"record":{"id":"4edfeb4801800709","repo":"juicedata/juicefs","slug":"drop-table-dirstats","errorCode":null,"errorMessage":"drop table dirStats","messagePattern":"drop table dirStats","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/sql.go","lineNumber":646,"sourceCode":"\n\tif ok {\n\t\tvar old Format\n\t\terr = json.Unmarshal([]byte(s.Value), &old)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"json: %s\", err)\n\t\t}\n\t\tif !old.DirStats && format.DirStats {\n\t\t\t// remove dir stats as they are outdated\n\t\t\terr = m.txn(func(s *xorm.Session) error {\n\t\t\t\t_, err := s.Where(\"TRUE\").Delete(new(dirStats))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tm.genLog(Background(), s, time.Now().UnixNano(), \"INIT_ENABLE_DIRSTATS()\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"drop table dirStats\")\n\t\t\t}\n\t\t}\n\t\tif !old.UserGroupQuota && format.UserGroupQuota {\n\t\t\t// remove user group quota as they are outdated\n\t\t\terr = m.txn(func(s *xorm.Session) error {\n\t\t\t\t_, err := s.Where(\"TRUE\").Delete(new(userGroupQuota))\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t\tm.genLog(Background(), s, time.Now().UnixNano(), \"INIT_ENABLE_USERGROUPQUOTA()\")\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"drop table userGroupQuota\")\n\t\t\t}\n\t\t}\n\t\tif err = format.update(&old, force); err != nil {\n\t\t\treturn errors.Wrap(err, \"update format\")","sourceCodeStart":628,"sourceCodeEnd":664,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/sql.go#L628-L664","documentation":"During `juicefs format` (doInit in the SQL metadata engine), when a volume previously had DirStats disabled and the new format enables it, all stale rows are deleted from the dirStats table inside a transaction. If that transactional DELETE fails (DB error, lock conflict, connection drop), the underlying database error is wrapped as \"drop table dirStats\" and format aborts.","triggerScenarios":"Running `juicefs format <sql-url> <name>` on an existing SQL (MySQL/Postgres/SQLite) volume whose stored format has DirStats=false while the new format has DirStats=true, and the DELETE FROM dirStats transaction fails due to a database error, lock timeout, or lost connection.","commonSituations":"Upgrading/re-formatting a volume to enable directory stats on a MySQL/Postgres server with lock waits or an unstable connection; DB user lacking DELETE privilege on the dirStats table; DB under heavy load causing deadlocks.","solutions":["Check DB connectivity and credentials, then retry `juicefs format`","Verify the metadata DB user has DELETE privilege on the dirStats table","Check DB error logs (wrapped error includes the cause) for lock timeouts/deadlocks and tune innodb_lock_wait_timeout or equivalent","If corruption is suspected, take a metadata backup (`juicefs dump`) and inspect the dirStats table"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before formatting, ensure connectivity\nerr := db.Ping()\nif err != nil { return fmt.Errorf(\"metadata DB unreachable: %w\", err) }","typeGuard":null,"tryCatchPattern":"if err := juicefsFormat(url, name); err != nil && strings.Contains(err.Error(), \"drop table dirStats\") {\n    // inspect wrapped cause, fix DB access/locks, then retry\n}","preventionTips":["Confirm DB user has DELETE privileges before reformatting","Reformat during low-traffic windows to avoid lock contention","Backup metadata with `juicefs dump` before changing format flags"],"tags":["database","sql","metadata","format"],"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-14T05:17:10.506Z"}