Not verified hands-on. This article was written from primary documentation rather than reproduced in an org, so it carries no tested-release badge. If you run it and something differs, say so in the comments and it gets tested and corrected.

The answer, briefly: the org is out of data storage, and data storage is counted separately from file storage. Being at 30% on files does not help you when data is at 100%. The error arrives on insert and looks like STORAGE_LIMIT_EXCEEDED with no further detail, because the platform has nothing useful to add.

Two buckets, counted separately

Salesforce tracks data storage and file storage as independent allocations. Filling one does not touch the other and does not borrow from it.

  • Data storage holds records. Accounts, Contacts, Cases, Tasks, custom object rows, field history rows.
  • File storage holds content. Files, attachments, Documents, Chatter file posts, static resources.

The confusing part is that a Content Version record consumes file storage for its body and a small amount of data storage for the row. So a heavy file estate shows up in both places, weighted heavily to one.

Records cost a flat 2 KB, not their field values

This is the single most useful fact about data storage, and it surprises people every time. Most records count as 2 KB each regardless of how many fields are populated. An Account with three fields filled in and an Account with two hundred fields filled in consume the same storage.

A few object types cost more per record. Person Accounts and Campaigns are the well-known exceptions, and they are priced higher because of what the platform stores behind them. Article types and a handful of others also differ. The principle holds: it is a per-record charge, not a per-byte one.

The consequence is that trimming fields saves nothing. Deleting records saves everything. An org drowning in storage almost always has a row-count problem in one or two objects, not a data-width problem spread across many.

What actually fills it

In practice the culprits are predictable:

  • Activities. Task and Event rows accumulate forever unless somebody archives them. An email-logging integration can add millions.
  • EmailMessage. Email-to-Case orgs generate one record per inbound and outbound message, plus the thread.
  • Field history. Every tracked change on every tracked field is a row. Tracking a frequently updated field on a high-volume object is the classic self-inflicted wound.
  • Integration logs. A custom object written on every callback, never purged, never looked at.
  • Converted and archived leads. They stay in data storage. Archiving is not deleting.
  • The recycle bin. Deleted records still count until they are purged, and the bin holds them for up to 15 days.

Finding the biggest objects

Setup gives you the answer directly. Search for Storage Usage and you get a breakdown by record type with row counts and storage consumed, plus the top users by storage. Start there before writing any query. It takes a minute and it is authoritative.

For growth rate rather than absolute size, count by month:

SELECT CALENDAR_YEAR(CreatedDate) yr, CALENDAR_MONTH(CreatedDate) mo,
       COUNT(Id) rows
FROM Task
GROUP BY CALENDAR_YEAR(CreatedDate), CALENDAR_MONTH(CreatedDate)
ORDER BY CALENDAR_YEAR(CreatedDate), CALENDAR_MONTH(CreatedDate)

A flat line means an old problem. A hockey stick means something was switched on, and finding what changed that month is usually faster than deleting anything.

Getting space back

In rough order of how much they return for the effort:

  • Empty the recycle bin. Free, instant, and reclaims whatever was deleted in the last fortnight. Setup has an org-wide bin separate from each user’s.
  • Hard delete old high-volume rows. Bulk API supports a hard delete operation that skips the bin entirely, which matters when you are deleting millions and do not want them sitting in storage for another 15 days.
  • Turn off field history tracking on fields nobody audits, then delete the existing history.
  • Move cold data to Big Objects. Big Object rows do not count against standard data storage. This is the intended destination for archived transactional data.
  • Buy more. Storage is a purchasable add-on, and for some orgs it is genuinely cheaper than an archiving project.

One caution on mass deletion: deleting parents cascades to children in master-detail, and triggers fire on delete. A delete job that fires a trigger doing callouts will fail in ways unrelated to storage.

Frequently asked

Why does my sandbox have different limits? Full sandboxes match production storage. Partial and developer sandboxes have much smaller fixed allocations. A refresh that fits in production can overflow a partial copy sandbox, and the fix is a template that excludes the large objects.

Do Big Objects really not count? They have their own allocation and are not part of the standard data storage figure. They are also not queryable in the normal way, which is the trade you are making.

Does deleting a record free the space immediately? No. It moves to the recycle bin and keeps consuming storage until it is purged or the bin is emptied.

Can I see storage by user? Yes, the same Storage Usage page lists the largest consumers. It is often one integration user, which tells you where to look next.