Published: October 29, 2026
Last updated: October 29, 2026

Summary

Expected when limits were configured as user scope quotas, not folder quotas:

  • Scope limits are persisted in users.user_data (backendScopes[].quota), exposed as scopes[].quota on GET /api/users.
  • The quotas table holds folder definitions only (folder Storage quota / /api/quotas).
  • quota_counters holds tracked usage (and reservations) for scope, share, and accounted folder quotas—often without any matching quotas row.

Applies to FileBrowser Quantum v2.1.0+ unless the persistence model changes.

Data model

KindLimit stored inUsage (when applicable)
Scopeusers.user_data → backendScopes[].quotaIndexed: index under user scope path. Accounted: quota_counters keyed by quota id.
FolderquotasIndexed: index at folder path. Accounted: quota_counters keyed by quotas.id.
Shareshares.share_settings → quotaLimitBytesAlways accounted → quota_counters with quota_id = share:<hash>.

No foreign key links quota_counters to quotas.

Code paths (reference)

  • GET /api/users scope limits: PrepForFrontend → GetFrontendScopes() → scopes[].quota (not from quotas).
  • Scope persist: sqldb.UserData.backendScopes; counters on save: OnUserScopeQuotaChanged.
  • Folder persist: CreateFolderQuota / UpdateFolderQuota → SaveFolderQuota.

What admins should do instead of DB work

GoalUI approach
Verify scope limitSettings → User management → user → source block; refresh or restart and re-open
Verify folder limitFolder → Storage quota; refresh or restart and re-open
Verify share limitShare edit / Settings → Shares; visitor usage bar on upload shares
Verify enforcementUpload within cap (success); exceed cap (quota error in UI)
Change or remove limitSame screen where it was created—never hand-edit SQLite

When to treat empty quotas as a bug

Only if folder quotas were configured (Storage quota or /api/quotas), GET /api/quotas?source=… returns them, and quotas is still empty after a full restart. That path should always call SaveFolderQuota.

Appendix: SQLite inspection (maintainers)

Use a copy of the database. Never instruct users to delete quota_counters rows manually; reset limits through the UI.

SQL
1
2
3
4
5
6
7
8
-- Scope limits (not in quotas)
SELECT username, user_data FROM users;

-- Folder limits only
SELECT id, source, path, user_id, limit_bytes, meter FROM quotas;

-- Tracked usage
SELECT quota_id, used_bytes, reserved_bytes FROM quota_counters;

API cross-check: GET /api/users → scopes[].quota; GET /api/quotas?source=… → folder; share APIs → quotaLimitBytes; GET /api/settings/sources → scopeQuota.