> For the complete documentation index, see [llms.txt](https://learn.capstorm.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://learn.capstorm.com/reference/copystorm-medic/delete-salesforce-records.md).

# Delete Salesforce Records

To access the Delete Salesforce Records tool:

* Select “Other Tools” from the top-level menu.
* Select “Rarely Used” and then “Delete Salesforce Records”

![](/files/GozUgBKw8OY5CzaKZkrC)

Understanding the consequences of deleting a hierarchy of records and even performing a hierarchical delete are difficult problems. Examples:

* What records will be deleted in Salesforce as a side effect if I delete the ACME account?
* Delete the following set of old Emails AND all of their related records.

The Delete Salesforce Records tool minimizes the effort required to understand, generate audit trails, and execute hierarchical type deletions.

The general flow of the Delete Salesforce Records tool is fairly simple.

* Select a Salesforce object as the root object for deletion (e.g. Account.)
* Use a record selector to identify top level records of this root object to delete.
* Optionally explore the records that will be deleted.
* Delete the selected records and all children using one of the following techniques:
  * Generate Data Loader files which can be use to manually delete records.
  * Generate a Python script which, when run, will delete the records.
  * Delete the records immediately using API calls to Salesforce.

The following sample screen shot illustrates that the *Account* Salesforce object is being selected.

![](/files/O44rcJAiMLYusdPh14Vg)

Once you have selected your Salesforce root object, you will be prompted to allow loading the relationship data for that object. This process may take a few seconds to complete. Upon completion you will be presented with a screen that shows these relationship details and the Select Records wizard tab at the top will be enabled.

![](/files/IJhQTDQkYI874wVSxW1O)

## Dependency Plans

In the screen shot above the left side of the relationships panel is a tree structure that represents the hierarchy of Salesforce relationship (or dependency) objects on the Salesforce root object that was selected earlier (Account in this example.) Throughout this document we will be making reference to this *Dependency Plan*, and in the current implementation of the Delete Salesforce Records tool, there is only one root Salesforce object for that plan. The terms *relationship* and *dependency* are interchangeable.

In this case the dependency plan is used to define rules for Salesforce record deletion. As one selects objects from the left-side dependency hierarchy tree, the dependency objects on that selection will appear on the right side along with some important metadata, as shown in the screen shot below.

![](/files/GvoL395vveyD48T0JBaT)

There are various ways in which rules can be applied surgically on each relationship object. One quick means is to right click on a relationship on the left side hierarchy tree and observe that a pop-up menu will be presented to the user, allowing for adding an exclusion rule, and possibly overriding the Cascade delete setting, as depicted in the screen shot below:

![](/files/G5VeJM7JXgjza2hgcWOH)

## Selecting Records to Delete

Once a specific Salesforce object has been selected, the Salesforce Ids of the top level records to be deleted must be specified. This is done using a Record Selector.

There are four ways to select top level record ids.

### **Snapshot**

The Snapshot record selector uses a previously created CopyStorm Snapshot to determine which records are candidates for deletion. When this option is selected the only deletion candidates that can occur are those that are both in the specified snapshot AND are in the selected Salesforce object table.

### **SOQL**

The SOQL record selector expects a SOQL statement which returns top level records Ids. For example, if the selected Salesforce root object is the Account object then any of the following SOQL statements would work.

* SELECT Id FROM Account WHERE name=’ACME’
* SELECT AccountId FROM Opportunity WHERE ShippingCountry=’Canada’

### **Id List**

The Id List record selector expects a text block containing top level set of record ids. A space or comma can be used to separate record ids. This is a useful selector when only a few top level records need to be deleted.

### **File**

The File record selector expects a text file with one Salesforce Id per line.

Once a Record Selector has been entered, click on the *Scan for Records* button to find all related records.

The following example screenshot used a SOQL record selector to specify which records will be deleted.

![](/files/auWGDMStkmDnvCvkUOnF)

## Understanding Deletion Candidates

Though it is possible at this point to start deleting records, it is often advisable to inspect the deletion candidates first. There are two clean ways to visualize what records will be deleted.

* Clicking on a candidate table will cause its related deletion candidate records to be display on the right side of the display.
* Generate a HTML report which show details about each record that will be deleted. This report can be useful as as audit trail.

Clicking on a candidate table causes a table with the following columns to be displayed.

* Salesforce Id — the Salesforce Id of the record to be deleted.
* Reference Field(s) — the name of fields in the record which point to other tables also in the deletion set.
* Parent Table(s) — the name of each table the reference fields in the record are pointing to.

In the following screen shot, the first Asset record in the list was included because:

* Three of its reference fields point to other tables in the deletion set (AccountId, ContactId, and RootAssetId)
* The tables the three reference fields are pointing to are Account, Contact, and Asset.

![](/files/Rj0ZYadVRjVJElgN3L8v)

For a complete audit trail and dependency details, the *Export* button is a good option

## Exporting Records

To export deletion candidates, click on the “Export” button.

![](/files/0fvMsob2tMJkAjtVimtE)

### Generating a HTML Report

To export a single-file HTML Report containing all of the record Ids that are marked to be deleted, click on the Generate HTML Report button.

The HTML report will include Record Ids and dependency information detailing why each individual record is included in the deletion plan.

### Generating Data Loader Files

To generate Data Load files click on the Generate Data Loader button and enter a output directory when prompted. The system will generate a series of 1 column text files where:

* The only column in each file is a Salesforce Record Id.
* Each file will be prefixed with a four digit number which indicates the order in which it should processed by Salesforce.

For example, the data loader files generated for the example is this document are:

```
#
# Record Deletion Plan Account
# Generated Mon Sep 18 10:48:07 CDT 2023
# Output Dir /home/greg/tmp/unittest
#
# The following files should be deleted from Salesforce in order.
#

0001CaseComment.txt
0002OpportunityContactRole.txt
0003QuoteLineItem.txt
0004OpportunityLineItem.txt
0005CaseFeed.txt
0006OpportunityFeed.txt
0007Case.txt
0008FeedItem.txt
0009Task.txt
0010AccountRelationship__c.txt
0011Quote.txt
0012Opportunity.txt
0013Asset.txt
0014Contact.txt
0015Account.txt
#
#
# End of Data Loader File Plan Account
#
```

### Generating Python

To generate a Python script which uses the CapStorm SQLForce library to delete records, click on the Generate Python button and enter an output directory when prompted. The system will generate a main python script and a directory of data files. Running the generated script will delete records from Salesforce.

## Deleting Records

The final step is to delete records from Salesforce using one of the following techniques.

* Generate Data Loader files which can be use to manually delete records.
* Generate a Python script which, when run, will delete the records.
* Delete the records immediately using API calls to Salesforce.

### Deleting Records Immediately

Clicking on the *Delete* button will prompt a user for confirmation and the rapidly start delete records from Salesforce. Before beginning the deletion, the confirmation dialog requires you to enter the Salesforce Org URL for the target Salesforce.

* The Salesforce Org URL (which appears as a somewhat randomly generated phrase) must be typed in by hand.
* If the deletion target is a production Salesforce instance then a checkbox must be selected.

![](/files/v5XiD44AMKD1DGZm0bgH)

<table><thead><tr><th width="192">Parameter</th><th width="111">Default</th><th width="74">Min</th><th width="99">Max</th><th>Description</th></tr></thead><tbody><tr><td>Records Per Batch</td><td>2000</td><td>1</td><td>50000</td><td>The maximum number of records to process concurrently. Reducing this value lowers memory usage during very large deletions.</td></tr><tr><td>Records Per Salesforce Request</td><td>200</td><td>1</td><td>200</td><td>The maximum number of records in a single API call to Salesforce. 200 is both the default and the hard ceiling imposed by the Salesforce API - this value cannot be set higher.</td></tr><tr><td>Concurrent Salesforce Requests</td><td>1</td><td>1</td><td>100</td><td>The maximum number of concurrent delete requests to send to Salesforce. Increasing this speeds up large deletions. Reduce this value if record locking errors are occurring frequently - a common symptom is retries appearing in the log.</td></tr><tr><td>Hard Delete</td><td>On</td><td>-</td><td>-</td><td>When enabled, records are permanently deleted and will not be placed in the Salesforce recycle bin. This is the default behavior. Requires the "Bulk API Hard Delete" permission in Salesforce. Uncheck this if you want deleted records to be recoverable from the recycle bin.</td></tr><tr><td>Validate Before Deletion</td><td>Off</td><td>-</td><td>-</td><td>When enabled, the system confirms each record still exists in Salesforce before issuing a delete request. Useful when time may have passed between scanning and deleting, and the record set may have changed.</td></tr><tr><td>Show Retry Reasons</td><td>Off</td><td>-</td><td>-</td><td>When enabled, if a deletion fails and the system retries, the retry reason is written to the log. The most common retry reason is record locking, which is typically resolved by reducing Concurrent Salesforce Requests.</td></tr><tr><td>Show Entity Delete Errors</td><td>Off</td><td>-</td><td>-</td><td>When enabled, an error is displayed when attempting to delete a record that is already deleted. These errors are generally safe to ignore and are off by default.</td></tr><tr><td>Show Invalid Cross Reference Error</td><td>Off</td><td>-</td><td>-</td><td>When enabled, an error is displayed for INVALID_CROSS_REFERENCE_KEY Salesforce errors. These are generally safe to ignore and are off by default.</td></tr></tbody></table>

![](/files/hlhC9yqkw1rsYdz8Cj5Q)

### Headless CLI

The Delete Salesforce Records tool can be run in headless batch mode using the standard CopyStorm/Medic command line interface. This is useful for scheduling automated deletion jobs via Windows Task Scheduler or cron on Linux.

To run in headless mode, first configure and test your deletion settings in the UI, then save a CopyStorm/Medic configuration file using File > Save As with the "Encrypted" and "Save Passwords" options selected. All deletion settings - including the dependency plan, record selector, and advanced options - are saved in this file.

The tool name for the `-tool` switch is `deleteTool`.

**Windows:**

```
CopyStormMedic.bat -tool deleteTool -run configFile.copyStormMedic
```

**Linux:**

```
sh CopyStormMedic.sh -tool deleteTool -run configFile.copyStormMedic
```

The `-tool` switch is case-insensitive - `deleteTool`, `deletetool`, and `DELETETOOL` are all valid.

The following global CopyStorm/Medic switches can be used to override values stored in the configuration file at runtime:

| Switch          | Parameter                 | Description                                                             |
| --------------- | ------------------------- | ----------------------------------------------------------------------- |
| `-sftype`       | `Sandbox` or `Production` | Override the Salesforce org type.                                       |
| `-sfuser`       | Username                  | Override the Salesforce username.                                       |
| `-sfpassword`   | Password                  | Override the Salesforce password.                                       |
| `-sftoken`      | Security Token            | Override the Salesforce security token.                                 |
| `-dbconnection` | Connection String         | Override the database connection string.                                |
| `-dbuser`       | Username                  | Override the database username.                                         |
| `-dbpassword`   | Password                  | Override the database password.                                         |
| `-dbschema`     | Schema Name               | Override the database schema.                                           |
| `-silent`       | -                         | Suppress stdout progress output. Does not affect behavior or exit code. |

There are no switches unique to `deleteTool` - all deletion configuration is controlled by the saved `.copyStormMedic` config file. The tool returns exit code `0` on success and `1` on failure.

For the full global command line reference see CopyStorm/Medic.

### XML Dependency Plan Configuration

The Delete Salesforce Records tool supports two user-provided XML override files that control which Salesforce objects are included in a deletion and in what order they are processed. These files do not replace the tool's built-in dependency logic - they are additive, meaning entries in your override files are merged on top of the built-in defaults.

> **Important:** Because external files are additive only, you cannot remove a built-in exclusion via an override file. You can only add new entries.

**File Locations**

Place override files in one of the following directories. The tool checks these locations in order and loads any file it finds:

| Priority | Path                                  |
| -------- | ------------------------------------- |
| 1        | `${copystorm.root}/config/<filename>` |
| 2        | `${capstorm.root}/config/<filename>`  |
| 3        | `${copystorm.config}/<filename>`      |
| 4        | `${capstorm.config}/<filename>`       |

These paths are controlled by Java system properties set by the product's startup scripts. If none of these properties are defined in your environment, no external override files will be discovered.

***

**File 1: `SalesforceDependencyPlanOptions.xml`**

This file controls which objects are excluded from deletion, which objects should have their Salesforce cascade-delete behavior overridden, forced deletion ordering between specific objects, and per-table performance tuning.

The filename must be exactly `SalesforceDependencyPlanOptions.xml`.

**Elements**

**`<ExcludeTable>`** - Excludes an object from the dependency plan entirely. Use `name` for an exact match or `pattern` for a case-insensitive Java regex match.

xml

```xml
<ExcludeTable name="MyAuditLog__c" />
<ExcludeTable pattern=".*__mdt" />
```

**`<CascadeDeleteIgnored>`** - Tells the tool to explicitly delete children of this object rather than relying on Salesforce's cascade-delete behavior. Use this when Salesforce's cascade-delete metadata for an object is unreliable.

xml

```xml
<CascadeDeleteIgnored name="CustomInvoice__c" />
```

**`<Dependency>`** - Forces a hard deletion ordering between two objects. The `child` object will always be deleted before the `parent` object. Both attributes are required. This is a hard constraint - if the ordering cannot be satisfied, the tool will throw an error rather than violate it.

xml

```xml
<Dependency parent="Invoice__c" child="LineItem__c" />
```

**`<DeleteTableRule>`** - Sets per-table performance tuning values. Use the special name `__default__` to set fallback values for all tables that don't have their own rule.

xml

```xml
<DeleteTableRule name="CustomBigTable__c" maxThreads="1" maxRequest="100" maxBatch="500" />
```

| Attribute    | Description                                                                   |
| ------------ | ----------------------------------------------------------------------------- |
| `name`       | Salesforce object API name, or `__default__` for the fallback rule. Required. |
| `maxThreads` | Max concurrent Salesforce API threads for this object. Optional.              |
| `maxRequest` | Max records per Salesforce API request for this object. Optional.             |
| `maxBatch`   | Max records to batch together. Optional.                                      |

**Full Example**

xml

```xml
<SalesforceDependencyPlanOptions>

    <!-- Exclude specific objects -->
    <ExcludeTable name="MyAuditLog__c" />
    <ExcludeTable name="LegacyArchive__c" />

    <!-- Exclude all objects matching a pattern -->
    <ExcludeTable pattern=".*__mdt" />
    <ExcludeTable pattern=".*ChangeEvent" />

    <!-- Explicitly delete children of this object rather than
         relying on Salesforce cascade-delete -->
    <CascadeDeleteIgnored name="CustomInvoice__c" />

    <!-- Force LineItem__c and Payment__c to be deleted
         before Invoice__c -->
    <Dependency parent="Invoice__c" child="LineItem__c" />
    <Dependency parent="Invoice__c" child="Payment__c" />

    <!-- Throttle deletion of a large object -->
    <DeleteTableRule name="CustomBigTable__c" maxThreads="1" maxRequest="100" />

</SalesforceDependencyPlanOptions>
```

***

**File 2: `SalesforceDependencyOverride.xml`**

This file handles cases where Salesforce's native relationship metadata does not correctly expose a parent-child relationship that the delete tool needs to follow. It lets you define a "parent as child" relationship so the tool discovers and deletes records it would otherwise miss.

The filename must be exactly `SalesforceDependencyOverride.xml`.

**Elements**

**`<ParentAsChild>`** - Adds a synthetic child relationship to a given object. All four attributes are required - if any are missing the element is silently skipped.

| Attribute          | Description                                                                 |
| ------------------ | --------------------------------------------------------------------------- |
| `tableName`        | The object that gets the synthetic child relationship added to it.          |
| `referenceField`   | The field on `tableName` that holds the foreign key pointing to the parent. |
| `parentTable`      | The parent object that will be treated as a child in the dependency tree.   |
| `relationshipName` | The name used to identify this relationship in the UI and dependency plan.  |

**Example**

xml

```xml
<SalesforceDependencyOverride>

    <!-- Treat ParentObject__c as a child of MyJunction__c,
         discovered via the ParentLookup__c field -->
    <ParentAsChild
        tableName="MyJunction__c"
        referenceField="ParentLookup__c"
        parentTable="ParentObject__c"
        relationshipName="ParentObjects"/>

</SalesforceDependencyOverride>
```

***

**Gotchas**

|                                                 | Detail                                                                                                                                    |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Additive only**                               | External files can only add entries - they cannot remove built-in exclusions or rules.                                                    |
| **Exact filenames required**                    | The filenames `SalesforceDependencyPlanOptions.xml` and `SalesforceDependencyOverride.xml` are hardcoded. Any other name will be ignored. |
| **`<Dependency>` is a hard constraint**         | If the forced ordering cannot be satisfied, the tool throws an error rather than silently reordering.                                     |
| **All 4 `<ParentAsChild>` attributes required** | If any attribute is blank or missing the element is silently skipped with no error.                                                       |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://learn.capstorm.com/reference/copystorm-medic/delete-salesforce-records.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
