apex-savepoint-and-rollback
Database.Savepoint / Database.rollback for partial-transaction undo: placement rules, ID reset, limit counters, nested savepoints, rollback after callout. NOT for Database.allOrNone=false partial success semantics (use apex-partial-dml). NOT for Queueable chained rollback (use apex-queueable-patterns).
Best use case
apex-savepoint-and-rollback is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Database.Savepoint / Database.rollback for partial-transaction undo: placement rules, ID reset, limit counters, nested savepoints, rollback after callout. NOT for Database.allOrNone=false partial success semantics (use apex-partial-dml). NOT for Queueable chained rollback (use apex-queueable-patterns).
Teams using apex-savepoint-and-rollback should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/apex-savepoint-and-rollback/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How apex-savepoint-and-rollback Compares
| Feature / Agent | apex-savepoint-and-rollback | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Database.Savepoint / Database.rollback for partial-transaction undo: placement rules, ID reset, limit counters, nested savepoints, rollback after callout. NOT for Database.allOrNone=false partial success semantics (use apex-partial-dml). NOT for Queueable chained rollback (use apex-queueable-patterns).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Apex Savepoint and Rollback
Activate when multi-step DML needs a safety net: if a later step fails, earlier steps should be undone. `Database.Savepoint` + `Database.rollback(sp)` is Salesforce's mechanism. The semantics are subtle: IDs on in-memory records are NOT reset, governor limits are not fully reset, and rollback after a callout is forbidden.
## Before Starting
- **Place the savepoint BEFORE the first DML** you might want to undo.
- **Never call `Database.rollback` after an HTTP callout in the same transaction.** Platform prevents it.
- **Clear Id fields manually after rollback** on in-memory records you intend to re-insert.
## Core Concepts
### The savepoint lifecycle
```
Savepoint sp = Database.setSavepoint();
try {
insert accounts;
insert contacts;
insert opportunities;
} catch (Exception e) {
Database.rollback(sp);
// handle
}
```
`setSavepoint()` snapshots the transaction; `rollback(sp)` undoes DML after the savepoint.
### What rollback undoes
- DML (insert/update/delete/upsert) after the savepoint
- Change to records' database state
### What rollback does NOT undo
- IDs populated on in-memory `SObject` instances (you must null them if re-inserting)
- Emails sent via `Messaging.sendEmail`
- HTTP callouts (and you can't even call rollback post-callout)
- Static variable state
- Governor limit counters are partially reset (DML rows yes; SOQL queries no)
### Nested savepoints
Valid; each call to `setSavepoint()` creates a new savepoint. Rolling back an outer savepoint invalidates inner ones.
### Limits
`Database.setSavepoint` counts against the 150 DML-statement limit. `Database.rollback` also counts. Avoid savepoint-per-record loops.
## Common Patterns
### Pattern: All-or-nothing multi-DML
```
Savepoint sp = Database.setSavepoint();
try {
insert parents;
insert children; // if this fails, parents rolled back too
} catch (DmlException e) {
Database.rollback(sp);
throw new MyException('Operation aborted', e);
}
```
### Pattern: Rollback-then-rethrow with clean IDs
```
Savepoint sp = Database.setSavepoint();
try {
insert accs;
insert opps;
} catch (Exception e) {
Database.rollback(sp);
for (Account a : accs) a.Id = null; // so retries can re-insert
throw e;
}
```
### Pattern: Pre-callout DML with deferred rollback decision
Rollback must happen before any callout. If you need conditional rollback based on callout response, do DML AFTER the callout, or don't use savepoints at all — use a compensating action.
## Decision Guidance
| Situation | Approach |
|---|---|
| Multi-step DML, all or nothing | Savepoint + try/catch + rollback |
| Partial success acceptable | Database.insert(records, false) |
| DML + callout + conditional rollback | Callout first, then DML (no savepoint needed) |
| Nested service-layer rollback | Caller sets savepoint; callees rely on it |
## Recommended Workflow
1. Identify the transaction boundary — where savepoint belongs.
2. Place `Database.setSavepoint()` before the first reversible DML.
3. Wrap remaining DML in try/catch; rollback in catch.
4. Null out IDs on in-memory records if retry is planned.
5. Verify NO callouts occur between savepoint and rollback.
6. Count savepoint + rollback against DML limit (each costs 1).
7. Test failure paths with forced exceptions to confirm rollback works.
## Review Checklist
- [ ] Savepoint placed before reversible DML
- [ ] No HTTP callouts between savepoint and rollback
- [ ] Rollback inside catch block, not in fall-through
- [ ] IDs nulled on in-memory records when retry expected
- [ ] No savepoint inside a loop
- [ ] Nested savepoints used sparingly and understood
- [ ] Test class with forced exception proves rollback
- [ ] Limits considered (savepoint + rollback = 2 DML statements)
## Salesforce-Specific Gotchas
1. **Rollback after callout throws `CalloutException`.** Order matters: DML-savepoint-DML-rollback OR callout-then-DML, never mix.
2. **IDs persist on in-memory records after rollback.** Database state is undone; Apex objects still carry IDs — re-inserting throws "Id already exists" if you don't null them.
3. **SOQL query count is NOT reset by rollback.** Only DML row counts partially reset. A rollback loop can still blow the SOQL-101 limit.
## Output Artifacts
| Artifact | Description |
|---|---|
| Transaction-boundary design | Where savepoints live in the service layer |
| Rollback helper | Utility that rolls back + nulls IDs |
| Test coverage | Force-fail case proving rollback |
## Related Skills
- `apex/apex-partial-dml` — all-or-none and partial DML options
- `apex/apex-exception-handling` — structured error handling
- `apex/apex-transaction-boundaries` — service-layer transaction designRelated Skills
apex-managed-sharing-patterns
Grant row-level access programmatically via __Share records when declarative sharing rules cannot express the policy. NOT for OWD, role hierarchy, or criteria-based sharing rule design.
lwc-imperative-apex
Call Apex methods imperatively from LWC — on button click, lifecycle hooks, or conditional logic. Covers import syntax, cacheable vs non-cacheable, async/await patterns, error handling, loading states, and Promise.all. NOT for wire service (use wire-service-patterns) and NOT for testing Apex mocks (use lwc-testing).
dataweave-for-apex
Use when transforming structured data inside Apex — CSV → JSON, XML → SObject list, JSON → flattened CSV, or schema-mapping a third-party payload to a Salesforce model — and the existing options (`JSON.deserialize`, `Dom.Document`, hand-written loops) are getting unwieldy. Triggers: 'apex transform csv json xml without external library', 'system.dataweave script', 'salesforce native dataweave apex execute', 'transform xml to sobject apex no mulesoft', 'json reshape salesforce apex script'. NOT for MuleSoft Anypoint DataWeave running off-platform (use mulesoft-anypoint-architecture), NOT for Apex JSON serialization basics (use apex-json-serialization), NOT for Bulk API CSV ingest (use bulk-api-2-patterns).
flow-rollback-patterns
Use the Flow Rollback Records element to undo DML inside the current transaction. Covers when rollback is appropriate vs catastrophic, how to combine with fault paths, partial-commit pitfalls, and the interaction with publish-after-commit Platform Events. NOT for external-system rollback (use compensation patterns). NOT for Database.SavePoint in Apex (use apex-transaction-control).
flow-invocable-from-apex
Author @InvocableMethod Apex classes that Flow can call as Actions. Design the input / output variable contract, bulk semantics (one list in, one list out), null handling, and error surfacing. Also covers the inverse direction: calling a flow from Apex via Flow.Interview. NOT for general Apex authoring (use apex-service-selector-domain). NOT for REST-exposed Apex (use apex-rest-resource-patterns).
flow-apex-defined-types
Design and use Apex-Defined Types as Flow variables for structured non-sObject data (HTTP callout payloads, External Service responses, complex configuration). Trigger keywords: apex-defined type, flow variable, @AuraEnabled class, flow http callout response. Does NOT cover building HTTP Callout Actions themselves, External Services schema, or raw Apex invocable methods.
rollback-and-hotfix-strategy
Planning and executing metadata rollbacks and emergency hotfixes in Salesforce orgs. Use when a production deployment causes regression and needs to be reverted, or when an urgent fix must bypass the normal release pipeline. Covers pre-deploy archive bundles, quick deploy for hotfixes, non-rollbackable component handling, and hotfix branch isolation. NOT for routine CI/CD pipeline setup (use continuous-integration-testing). NOT for destructive changes authoring (use destructive-changes-deployment).
scheduled-apex-failure-detection-and-monitoring
Use when nightly batch / scheduled Apex jobs are failing without anyone noticing — covers why uncaught exceptions in `execute()` go to the debug log instead of email, how to query `AsyncApexJob` for `Status`, `NumberOfErrors`, and `ExtendedStatus`, when to implement `Database.RaisesPlatformEvents` so the platform publishes `BatchApexErrorEvent` on uncaught failures, how to subscribe to that event with an Apex trigger and notify operators, and how to layer a custom watcher schedule on top so silent-failure modes (job that never started, scheduled class deleted, queue stuck on `Queued`) still surface. Triggers: 'nightly batch failed at 2am with no notification', 'how do we know if a scheduled apex job is failing', 'BatchApexErrorEvent vs custom retry logic', 'Setup Apex Jobs only shows last 7 days, where else can I look', 'job is stuck in queued status nobody noticed for a week'. NOT for general Apex exception handling patterns (use apex/apex-exception-handling-and-logging), NOT for Batch Apex authoring or chunking strategy (use apex/batch-apex-design), NOT for Setup → Apex Jobs UI walkthrough as an admin task (use admin/batch-job-scheduling-and-monitoring), NOT for retry logic itself (use apex/scheduled-apex-retry-patterns once authored).
platform-events-apex
Use when publishing or subscribing to Salesforce Platform Events from Apex, comparing Platform Events with Change Data Capture, or designing event-triggered error handling and monitoring. Triggers: 'EventBus.publish', 'platform event trigger', 'CDC vs Platform Events', 'replay ID', 'high-volume event'. NOT for Flow-only publish/subscribe automation.
health-cloud-apex-extensions
Use this skill when extending Health Cloud via Apex: implementing HealthCloudGA managed-package interfaces, automating care plan lifecycle hooks, processing referrals using Industries Common Components invocable actions, or enforcing HIPAA-compliant logging governance for clinical Apex code. Trigger keywords: CarePlanProcessorCallback, HealthCloudGA namespace, ReferralRequest, ReferralResponse, care plan invocable actions, clinical Apex extension, Health Cloud Apex API. NOT for standard Apex triggers or generic Apex development unrelated to Health Cloud managed-package extension points.
fsl-apex-extensions
Use when writing Apex that calls Field Service Lightning scheduling APIs — AppointmentBookingService, ScheduleService, GradeSlotsService, or OAAS — to book, schedule, grade, or optimize service appointments programmatically. Trigger keywords: FSL Apex namespace, GetSlots, schedule service appointment via code, appointment booking API, FSL optimization API. NOT for standard Apex patterns unrelated to FSL, admin-level scheduling policy configuration, or declarative FSL scheduling.
fsc-apex-extensions
Use this skill when extending Financial Services Cloud (FSC) behavior through Apex: customizing financial rollup recalculation, disabling built-in FSC triggers to write custom trigger logic, implementing Compliant Data Sharing (CDS) participant/role integrations, or building custom FSC action handlers. NOT for standard Apex unrelated to the FSC managed package, standard Salesforce sharing rules, or configuring FSC rollups through the Admin UI — use the admin/financial-account-setup skill for declarative rollup setup.