or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdbulk-operations.mdbulk2-operations.mdexceptions.mdindex.mdmetadata-api.mdrest-api.mdutilities.md

exceptions.mddocs/

0

# Exception Classes and Error Handling

1

2

Comprehensive exception hierarchy mapping HTTP status codes and Salesforce errors to specific Python exceptions for precise error handling and debugging. The simple-salesforce library provides detailed error information to help developers identify and resolve issues quickly.

3

4

## Base Exception Class

5

6

The foundation exception class that all other Salesforce-specific exceptions inherit from.

7

8

```python { .api }

9

class SalesforceError(Exception):

10

def __init__(self, url, status, resource_name, content):

11

"""

12

Base exception for all Salesforce API errors.

13

14

Parameters:

15

- url: API endpoint URL where error occurred

16

- status: HTTP status code

17

- resource_name: Salesforce resource or operation name

18

- content: Response content with error details

19

20

Attributes:

21

- url: The API endpoint URL

22

- status: HTTP status code

23

- resource_name: Resource identifier

24

- content: Raw error response content

25

"""

26

self.url = url

27

self.status = status

28

self.resource_name = resource_name

29

self.content = content

30

31

# Create detailed error message

32

message = f"Error Code: {status}"

33

if resource_name:

34

message += f", Resource: {resource_name}"

35

if url:

36

message += f", URL: {url}"

37

38

super().__init__(message)

39

```

40

41

## HTTP Status Code Exceptions

42

43

Specific exceptions mapped to HTTP status codes for precise error handling.

44

45

```python { .api }

46

class SalesforceMoreThanOneRecord(SalesforceError):

47

"""

48

Error Code 300: Multiple Choice

49

50

Raised when a query or operation returns multiple records but only one was expected.

51

Common in get operations with non-unique identifiers.

52

"""

53

54

class SalesforceMalformedRequest(SalesforceError):

55

"""

56

Error Code 400: Bad Request

57

58

Raised when the request is malformed, has invalid parameters, or contains

59

invalid data. Check request syntax, required fields, and data formats.

60

"""

61

62

class SalesforceExpiredSession(SalesforceError):

63

"""

64

Error Code 401: Unauthorized

65

66

Raised when the session has expired or authentication credentials are invalid.

67

Requires re-authentication or session refresh.

68

"""

69

70

class SalesforceRefusedRequest(SalesforceError):

71

"""

72

Error Code 403: Forbidden

73

74

Raised when the request is refused due to insufficient permissions.

75

The user may lack required object or field-level permissions.

76

"""

77

78

class SalesforceResourceNotFound(SalesforceError):

79

"""

80

Error Code 404: Not Found

81

82

Raised when the requested resource, record, or endpoint does not exist.

83

Verify record IDs, object names, and API endpoints.

84

"""

85

```

86

87

## Authentication and General Exceptions

88

89

Specialized exceptions for authentication failures and general Salesforce errors.

90

91

```python { .api }

92

class SalesforceAuthenticationFailed(SalesforceError):

93

"""

94

Authentication failure exception.

95

96

Raised during login when credentials are invalid, security tokens are wrong,

97

or authentication methods are not properly configured.

98

"""

99

100

class SalesforceGeneralError(SalesforceError):

101

"""

102

General Salesforce error for unspecified issues.

103

104

Raised for Salesforce-specific errors that don't fit other categories,

105

such as org limits, configuration issues, or service unavailability.

106

"""

107

```

108

109

## Bulk API v2.0 Exceptions

110

111

Specialized exceptions for Bulk API v2.0 operations with enhanced error details.

112

113

```python { .api }

114

class SalesforceOperationError(SalesforceError):

115

"""

116

Base exception for Bulk API v2.0 operation errors.

117

118

Provides additional context for bulk operation failures including

119

job information and processing details.

120

"""

121

122

class SalesforceBulkV2LoadError(SalesforceOperationError):

123

"""

124

Bulk API v2.0 data load/ingest error.

125

126

Raised when bulk insert, update, upsert, or delete operations fail.

127

Contains details about failed records and validation errors.

128

"""

129

130

class SalesforceBulkV2ExtractError(SalesforceOperationError):

131

"""

132

Bulk API v2.0 data extraction/query error.

133

134

Raised when bulk query operations fail due to query syntax errors,

135

resource limitations, or data access issues.

136

"""

137

```

138

139

## Exception Handling Patterns

140

141

### Basic Exception Handling

142

143

```python

144

from simple_salesforce import (

145

Salesforce,

146

SalesforceAuthenticationFailed,

147

SalesforceExpiredSession,

148

SalesforceResourceNotFound,

149

SalesforceMalformedRequest,

150

SalesforceRefusedRequest,

151

SalesforceError

152

)

153

154

try:

155

sf = Salesforce(

156

username='user@example.com',

157

password='password',

158

security_token='token'

159

)

160

161

# Perform operations

162

account = sf.Account.get('001XX000003DHPr')

163

164

except SalesforceAuthenticationFailed as e:

165

print(f"Authentication failed: {e}")

166

print("Check username, password, and security token")

167

168

except SalesforceExpiredSession as e:

169

print(f"Session expired: {e}")

170

print("Re-authenticate to get new session")

171

172

except SalesforceResourceNotFound as e:

173

print(f"Resource not found: {e}")

174

print("Verify the record ID exists")

175

176

except SalesforceMalformedRequest as e:

177

print(f"Bad request: {e}")

178

print("Check request parameters and data format")

179

180

except SalesforceRefusedRequest as e:

181

print(f"Access denied: {e}")

182

print("Check user permissions for this operation")

183

184

except SalesforceError as e:

185

print(f"General Salesforce error: {e}")

186

print(f"Status: {e.status}")

187

print(f"URL: {e.url}")

188

print(f"Content: {e.content}")

189

```

190

191

### Advanced Exception Analysis

192

193

```python

194

def analyze_salesforce_error(error):

195

"""

196

Analyze Salesforce error and provide detailed diagnostics.

197

198

Parameters:

199

- error: SalesforceError exception instance

200

201

Returns:

202

dict: Detailed error analysis and suggested actions

203

"""

204

205

analysis = {

206

'error_type': type(error).__name__,

207

'status_code': getattr(error, 'status', None),

208

'url': getattr(error, 'url', None),

209

'resource': getattr(error, 'resource_name', None),

210

'content': getattr(error, 'content', None),

211

'suggestions': []

212

}

213

214

# Parse error content for additional details

215

if hasattr(error, 'content') and error.content:

216

try:

217

import json

218

if isinstance(error.content, str):

219

content_data = json.loads(error.content)

220

else:

221

content_data = error.content

222

223

if isinstance(content_data, list) and len(content_data) > 0:

224

error_detail = content_data[0]

225

analysis['error_code'] = error_detail.get('errorCode')

226

analysis['message'] = error_detail.get('message')

227

analysis['fields'] = error_detail.get('fields', [])

228

except:

229

# Content is not JSON or not parseable

230

pass

231

232

# Add specific suggestions based on error type

233

if isinstance(error, SalesforceAuthenticationFailed):

234

analysis['suggestions'].extend([

235

"Verify username and password are correct",

236

"Check if security token is required and valid",

237

"Ensure the user account is not locked or deactivated",

238

"Verify the correct Salesforce domain (login vs test)"

239

])

240

241

elif isinstance(error, SalesforceExpiredSession):

242

analysis['suggestions'].extend([

243

"Re-authenticate to obtain a fresh session",

244

"Check session timeout settings",

245

"Implement session refresh logic for long-running processes"

246

])

247

248

elif isinstance(error, SalesforceResourceNotFound):

249

analysis['suggestions'].extend([

250

"Verify the record ID is valid and exists",

251

"Check if the object type is correct",

252

"Ensure the record hasn't been deleted",

253

"Verify API endpoint URLs are correct"

254

])

255

256

elif isinstance(error, SalesforceMalformedRequest):

257

analysis['suggestions'].extend([

258

"Check required fields are provided",

259

"Verify field names match the object schema",

260

"Ensure data types match field requirements",

261

"Check for invalid characters or formatting"

262

])

263

264

elif isinstance(error, SalesforceRefusedRequest):

265

analysis['suggestions'].extend([

266

"Check user has appropriate object permissions",

267

"Verify field-level security settings",

268

"Check if user has required profile or permission sets",

269

"Verify organization-wide defaults allow access"

270

])

271

272

return analysis

273

274

# Usage

275

try:

276

result = sf.Account.create({

277

'Name': '', # Empty required field

278

'InvalidField__c': 'value' # Non-existent field

279

})

280

except SalesforceError as e:

281

error_analysis = analyze_salesforce_error(e)

282

283

print(f"Error Type: {error_analysis['error_type']}")

284

print(f"Status: {error_analysis['status_code']}")

285

286

if 'message' in error_analysis:

287

print(f"Message: {error_analysis['message']}")

288

289

if error_analysis['suggestions']:

290

print("Suggestions:")

291

for suggestion in error_analysis['suggestions']:

292

print(f" - {suggestion}")

293

```

294

295

### Bulk Operations Error Handling

296

297

```python

298

def handle_bulk_errors(bulk_results, operation_type="bulk operation"):

299

"""

300

Handle and analyze bulk operation errors.

301

302

Parameters:

303

- bulk_results: Results from bulk operation

304

- operation_type: Description of the operation for logging

305

306

Returns:

307

dict: Error analysis and failed record details

308

"""

309

310

successful_records = []

311

failed_records = []

312

error_summary = {}

313

314

for i, result in enumerate(bulk_results):

315

if result.get('success', False):

316

successful_records.append(i)

317

else:

318

failed_records.append({

319

'index': i,

320

'error': result.get('error', 'Unknown error'),

321

'id': result.get('id'),

322

'result': result

323

})

324

325

# Categorize errors

326

error_msg = result.get('error', 'Unknown')

327

error_type = error_msg.split(':')[0] if ':' in error_msg else error_msg

328

error_summary[error_type] = error_summary.get(error_type, 0) + 1

329

330

success_rate = (len(successful_records) / len(bulk_results)) * 100 if bulk_results else 0

331

332

print(f"{operation_type.title()} Results:")

333

print(f" Total records: {len(bulk_results)}")

334

print(f" Successful: {len(successful_records)}")

335

print(f" Failed: {len(failed_records)}")

336

print(f" Success rate: {success_rate:.1f}%")

337

338

if error_summary:

339

print(" Error breakdown:")

340

for error_type, count in error_summary.items():

341

print(f" {error_type}: {count}")

342

343

return {

344

'success_count': len(successful_records),

345

'failure_count': len(failed_records),

346

'success_rate': success_rate,

347

'failed_records': failed_records,

348

'error_summary': error_summary

349

}

350

351

# Usage with bulk operations

352

try:

353

bulk_data = [

354

{'Name': 'Valid Account', 'Type': 'Customer'},

355

{'Name': '', 'Type': 'Customer'}, # Will fail - empty Name

356

{'Name': 'Another Valid Account', 'InvalidField': 'value'} # Will fail - invalid field

357

]

358

359

results = sf.bulk.Account.insert(bulk_data, include_detailed_results=True)

360

error_analysis = handle_bulk_errors(results, "bulk insert")

361

362

# Handle failed records

363

if error_analysis['failed_records']:

364

print("\nFailed record details:")

365

for failed in error_analysis['failed_records']:

366

print(f" Record {failed['index']}: {failed['error']}")

367

368

except SalesforceError as e:

369

print(f"Bulk operation failed entirely: {e}")

370

```

371

372

### Retry Logic with Exception Handling

373

374

```python

375

import time

376

import random

377

378

def retry_with_backoff(operation_func, max_retries=3, base_delay=1, max_delay=60):

379

"""

380

Retry operations with exponential backoff and exception handling.

381

382

Parameters:

383

- operation_func: Function to retry

384

- max_retries: Maximum number of retry attempts

385

- base_delay: Initial delay between retries

386

- max_delay: Maximum delay between retries

387

388

Returns:

389

Result of successful operation

390

391

Raises:

392

Last exception if all retries fail

393

"""

394

395

last_exception = None

396

397

for attempt in range(max_retries + 1):

398

try:

399

return operation_func()

400

401

except SalesforceExpiredSession as e:

402

print(f"Attempt {attempt + 1}: Session expired, re-authenticating...")

403

# Re-authentication would happen here

404

last_exception = e

405

406

except SalesforceRefusedRequest as e:

407

# Don't retry permission errors

408

print(f"Permission denied, not retrying: {e}")

409

raise

410

411

except SalesforceResourceNotFound as e:

412

# Don't retry for missing resources

413

print(f"Resource not found, not retrying: {e}")

414

raise

415

416

except (SalesforceMalformedRequest, SalesforceGeneralError) as e:

417

print(f"Attempt {attempt + 1}: Transient error, retrying... {e}")

418

last_exception = e

419

420

except SalesforceError as e:

421

print(f"Attempt {attempt + 1}: Unknown Salesforce error: {e}")

422

last_exception = e

423

424

# Calculate delay with exponential backoff and jitter

425

if attempt < max_retries:

426

delay = min(base_delay * (2 ** attempt), max_delay)

427

jitter = random.uniform(0, 0.1) * delay # Add up to 10% jitter

428

total_delay = delay + jitter

429

430

print(f"Waiting {total_delay:.1f} seconds before retry...")

431

time.sleep(total_delay)

432

433

# All retries exhausted

434

raise last_exception

435

436

# Usage

437

def risky_operation():

438

return sf.query("SELECT Id, Name FROM Account LIMIT 10")

439

440

try:

441

results = retry_with_backoff(risky_operation, max_retries=3)

442

print(f"Operation succeeded: {len(results['records'])} records")

443

444

except SalesforceError as e:

445

print(f"Operation failed after all retries: {e}")

446

```

447

448

### Context Manager for Error Handling

449

450

```python

451

from contextlib import contextmanager

452

453

@contextmanager

454

def salesforce_error_context(operation_name="Salesforce operation"):

455

"""

456

Context manager for comprehensive Salesforce error handling.

457

458

Parameters:

459

- operation_name: Name of the operation for logging

460

"""

461

462

try:

463

yield

464

465

except SalesforceAuthenticationFailed as e:

466

print(f"{operation_name} failed: Authentication error")

467

print("Suggestion: Check credentials and re-authenticate")

468

raise

469

470

except SalesforceExpiredSession as e:

471

print(f"{operation_name} failed: Session expired")

472

print("Suggestion: Refresh session and retry")

473

raise

474

475

except SalesforceResourceNotFound as e:

476

print(f"{operation_name} failed: Resource not found")

477

print(f"URL: {e.url}")

478

print("Suggestion: Verify record IDs and object names")

479

raise

480

481

except SalesforceMalformedRequest as e:

482

print(f"{operation_name} failed: Bad request")

483

print(f"Status: {e.status}")

484

if hasattr(e, 'content'):

485

print(f"Details: {e.content}")

486

print("Suggestion: Check request format and required fields")

487

raise

488

489

except SalesforceRefusedRequest as e:

490

print(f"{operation_name} failed: Permission denied")

491

print("Suggestion: Check user permissions and sharing settings")

492

raise

493

494

except SalesforceError as e:

495

print(f"{operation_name} failed: General Salesforce error")

496

print(f"Error type: {type(e).__name__}")

497

print(f"Status: {e.status}")

498

print(f"URL: {e.url}")

499

raise

500

501

except Exception as e:

502

print(f"{operation_name} failed: Unexpected error")

503

print(f"Error type: {type(e).__name__}")

504

print(f"Message: {str(e)}")

505

raise

506

507

# Usage

508

with salesforce_error_context("Account creation"):

509

new_account = sf.Account.create({

510

'Name': 'Test Account',

511

'Type': 'Customer'

512

})

513

print(f"Created account: {new_account['id']}")

514

515

with salesforce_error_context("Bulk insert operation"):

516

results = sf.bulk.Contact.insert(contact_data)

517

handle_bulk_errors(results, "contact insert")

518

```

519

520

## Error Prevention Best Practices

521

522

### Input Validation

523

524

```python

525

def validate_salesforce_input(data, object_type=None):

526

"""

527

Validate data before Salesforce operations to prevent errors.

528

529

Parameters:

530

- data: Record data dictionary or list of records

531

- object_type: Salesforce object type for schema validation

532

533

Returns:

534

dict: Validation results with errors and warnings

535

"""

536

537

errors = []

538

warnings = []

539

540

# Handle single record or list

541

records = data if isinstance(data, list) else [data]

542

543

for i, record in enumerate(records):

544

record_prefix = f"Record {i+1}: " if len(records) > 1 else ""

545

546

# Check for None values

547

if not record:

548

errors.append(f"{record_prefix}Empty record")

549

continue

550

551

# Check for required Name field (common requirement)

552

if 'Name' in record and not record['Name']:

553

errors.append(f"{record_prefix}Name field is empty")

554

555

# Check field name format (no spaces, proper case)

556

for field_name in record.keys():

557

if ' ' in field_name:

558

warnings.append(f"{record_prefix}Field '{field_name}' contains spaces")

559

560

# Check for potential typos in common fields

561

common_typos = {

562

'name': 'Name',

563

'type': 'Type',

564

'email': 'Email',

565

'phone': 'Phone'

566

}

567

568

if field_name.lower() in common_typos and field_name != common_typos[field_name.lower()]:

569

warnings.append(

570

f"{record_prefix}Field '{field_name}' might be '{common_typos[field_name.lower()]}'"

571

)

572

573

# Check for very long text values

574

for field_name, value in record.items():

575

if isinstance(value, str) and len(value) > 255:

576

warnings.append(

577

f"{record_prefix}Field '{field_name}' is very long ({len(value)} chars)"

578

)

579

580

return {

581

'valid': len(errors) == 0,

582

'errors': errors,

583

'warnings': warnings,

584

'record_count': len(records)

585

}

586

587

# Usage

588

account_data = {

589

'Name': 'Test Account',

590

'type': 'Customer', # Should be 'Type'

591

'Description': 'A' * 300 # Very long description

592

}

593

594

validation = validate_salesforce_input(account_data)

595

596

if not validation['valid']:

597

print("Validation errors:")

598

for error in validation['errors']:

599

print(f" {error}")

600

601

if validation['warnings']:

602

print("Validation warnings:")

603

for warning in validation['warnings']:

604

print(f" {warning}")

605

606

if validation['valid']:

607

# Proceed with operation

608

try:

609

result = sf.Account.create(account_data)

610

except SalesforceError as e:

611

error_analysis = analyze_salesforce_error(e)

612

```

613

614

### Proactive Error Detection

615

616

```python

617

def check_salesforce_connectivity(sf):

618

"""

619

Check Salesforce connectivity and basic functionality.

620

621

Parameters:

622

- sf: Salesforce client instance

623

624

Returns:

625

dict: Connectivity status and any issues found

626

"""

627

628

status = {

629

'connected': False,

630

'session_valid': False,

631

'api_accessible': False,

632

'errors': [],

633

'warnings': []

634

}

635

636

try:

637

# Test basic connectivity

638

limits = sf.limits()

639

status['connected'] = True

640

status['api_accessible'] = True

641

642

# Check API usage

643

if hasattr(sf, 'api_usage') and sf.api_usage:

644

if 'api-usage' in sf.api_usage:

645

usage = sf.api_usage['api-usage']

646

usage_percent = (usage.used / usage.total) * 100

647

648

if usage_percent > 90:

649

status['warnings'].append(f"API usage very high: {usage_percent:.1f}%")

650

elif usage_percent > 75:

651

status['warnings'].append(f"API usage high: {usage_percent:.1f}%")

652

653

# Test session validity

654

try:

655

sf.describe()

656

status['session_valid'] = True

657

except SalesforceExpiredSession:

658

status['errors'].append("Session has expired")

659

660

except SalesforceAuthenticationFailed:

661

status['errors'].append("Authentication failed")

662

except SalesforceError as e:

663

status['errors'].append(f"Salesforce error: {e}")

664

except Exception as e:

665

status['errors'].append(f"Connection error: {e}")

666

667

return status

668

669

# Usage

670

connectivity = check_salesforce_connectivity(sf)

671

672

if not connectivity['connected']:

673

print("Salesforce connectivity issues:")

674

for error in connectivity['errors']:

675

print(f" {error}")

676

else:

677

print("Salesforce connection OK")

678

679

if connectivity['warnings']:

680

print("Warnings:")

681

for warning in connectivity['warnings']:

682

print(f" {warning}")

683

```