generalbots/botbook/src/04-basic-scripting/keyword-on-error.md
Rodrigo Rodriguez (Pragmatismo) 037db5c381 feat: Major workspace reorganization and documentation update
- Add comprehensive documentation in botbook/ with 12 chapters
- Add botapp/ Tauri desktop application
- Add botdevice/ IoT device support
- Add botlib/ shared library crate
- Add botmodels/ Python ML models service
- Add botplugin/ browser extension
- Add botserver/ reorganized server code
- Add bottemplates/ bot templates
- Add bottest/ integration tests
- Add botui/ web UI server
- Add CI/CD workflows in .forgejo/workflows/
- Add AGENTS.md and PROD.md documentation
- Add dependency management scripts (DEPENDENCIES.sh/ps1)
- Remove legacy src/ structure and migrations
- Clean up temporary and backup files
2026-04-19 08:14:25 -03:00

10 KiB

ON ERROR RESUME NEXT

The ON ERROR RESUME NEXT keyword enables BASIC error handling, allowing scripts to continue execution when errors occur instead of terminating immediately.


Syntax

ON ERROR RESUME NEXT    ' Enable error trapping
ON ERROR GOTO 0         ' Disable error trapping

Description

ON ERROR RESUME NEXT enables error trapping mode where execution continues to the next statement after an error occurs, rather than halting the script. This pattern is borrowed from BASIC and provides a simple way to handle errors gracefully in BASIC scripts.

When error trapping is enabled:

  • Errors are captured but don't stop execution
  • The ERROR function returns TRUE if an error occurred
  • The ERROR MESSAGE function returns the error description
  • The ERR variable contains the error number

Use ON ERROR GOTO 0 to disable error trapping and restore normal error behavior.


Error State Keywords

Keyword Description Example
ON ERROR RESUME NEXT Enable error trapping ON ERROR RESUME NEXT
ON ERROR GOTO 0 Disable error trapping ON ERROR GOTO 0
ERROR Returns TRUE if error occurred IF ERROR THEN
ERROR MESSAGE Get last error message msg = ERROR MESSAGE
ERR Get error number code = ERR
CLEAR ERROR Clear error state CLEAR ERROR
THROW Raise a custom error THROW "Invalid input"
ASSERT Assert a condition ASSERT count > 0, "Count must be positive"

Examples

Basic Error Handling

' Enable error trapping
ON ERROR RESUME NEXT

' Attempt a risky operation
result = GET "https://api.example.com/data"

' Check if it failed
IF ERROR THEN
    TALK "Sorry, I couldn't fetch the data: " + ERROR MESSAGE
ELSE
    TALK "Data retrieved successfully!"
END IF

Multiple Operations with Error Checking

ON ERROR RESUME NEXT

' Try to read a file
content = READ "config.csv"
IF ERROR THEN
    TALK "Config file not found, using defaults"
    CLEAR ERROR
    content = "name,value\ndefault,true"
END IF

' Try to parse it
data = PARSE_CSV(content)
IF ERROR THEN
    TALK "Failed to parse config: " + ERROR MESSAGE
    CLEAR ERROR
END IF

' Continue with whatever data we have
TALK "Loaded " + LEN(data) + " configuration entries"

Database Operations

ON ERROR RESUME NEXT

' Try to insert a record
INSERT "customers", #{
    "name": customer_name,
    "email": customer_email,
    "created_at": NOW()
}

IF ERROR THEN
    IF INSTR(ERROR MESSAGE, "duplicate") > 0 THEN
        TALK "This customer already exists in our system."
    ELSE IF INSTR(ERROR MESSAGE, "connection") > 0 THEN
        TALK "Database is temporarily unavailable. Please try again."
    ELSE
        TALK "Could not save customer: " + ERROR MESSAGE
    END IF
ELSE
    TALK "Customer saved successfully!"
END IF

ON ERROR GOTO 0  ' Disable error trapping

HTTP Request with Fallback

ON ERROR RESUME NEXT

' Try primary API
data = GET "https://primary-api.example.com/endpoint"

IF ERROR THEN
    PRINT "Primary API failed: " + ERROR MESSAGE
    CLEAR ERROR
    
    ' Try fallback API
    data = GET "https://fallback-api.example.com/endpoint"
    
    IF ERROR THEN
        TALK "Both APIs are unavailable. Please try again later."
        RETURN
    END IF
END IF

' Process the data
TALK "Retrieved: " + data.name

File Operations with Cleanup

ON ERROR RESUME NEXT

' Generate a report
report = GENERATE PDF "templates/report.html", report_data, "temp/report.pdf"

IF ERROR THEN
    TALK "Failed to generate report: " + ERROR MESSAGE
    CLEAR ERROR
ELSE
    ' Try to send it
    SEND MAIL recipient, "Your Report", "Please find your report attached.", [report.localName]
    
    IF ERROR THEN
        TALK "Report generated but email failed: " + ERROR MESSAGE
        DOWNLOAD report.url AS "report.pdf"
        TALK "You can download it directly instead."
    ELSE
        TALK "Report sent successfully!"
    END IF
    
    ' Clean up temp file
    DELETE "temp/report.pdf"
    ' Ignore cleanup errors
    CLEAR ERROR
END IF

ON ERROR GOTO 0

Validation with ASSERT

ON ERROR RESUME NEXT

' Validate input
ASSERT LEN(email) > 0, "Email is required"
IF ERROR THEN
    TALK ERROR MESSAGE
    RETURN
END IF

ASSERT INSTR(email, "@") > 0, "Invalid email format"
IF ERROR THEN
    TALK ERROR MESSAGE
    RETURN
END IF

ASSERT amount > 0, "Amount must be positive"
IF ERROR THEN
    TALK ERROR MESSAGE
    RETURN
END IF

' All validations passed
TALK "Processing your request..."

Custom Error with THROW

ON ERROR RESUME NEXT

' Check business rules
IF quantity > inventory_count THEN
    THROW "Insufficient inventory: only " + inventory_count + " items available"
END IF

IF customer_credit < total_price THEN
    THROW "Insufficient credit: need $" + FORMAT(total_price - customer_credit, "#,##0.00") + " more"
END IF

' Check for errors from THROW
IF ERROR THEN
    TALK "Cannot process order: " + ERROR MESSAGE
    RETURN
END IF

' Continue with order processing
TALK "Order confirmed!"

Loop with Error Recovery

ON ERROR RESUME NEXT

successful = 0
failed = 0

FOR EACH item IN items_to_process
    ' Process each item
    result = POST "https://api.example.com/process", item
    
    IF ERROR THEN
        PRINT "Failed to process item " + item.id + ": " + ERROR MESSAGE
        failed = failed + 1
        CLEAR ERROR  ' Clear error to continue loop
    ELSE
        successful = successful + 1
    END IF
NEXT

ON ERROR GOTO 0

TALK "Processing complete: " + successful + " succeeded, " + failed + " failed"

Nested Error Handling

ON ERROR RESUME NEXT

' Outer operation
connection = CONNECT "database"

IF ERROR THEN
    TALK "Database connection failed"
    RETURN
END IF

' Inner operation
ON ERROR RESUME NEXT
result = QUERY connection, "SELECT * FROM users"

IF ERROR THEN
    TALK "Query failed, trying alternative..."
    CLEAR ERROR
    result = QUERY connection, "SELECT * FROM users_backup"
END IF

IF ERROR THEN
    TALK "All queries failed: " + ERROR MESSAGE
ELSE
    TALK "Found " + LEN(result) + " users"
END IF

ON ERROR GOTO 0

Error Codes

Common error codes returned by ERR:

Code Category Description
1xxx Network HTTP and connection errors
2xxx Database SQL and data errors
3xxx File File system errors
4xxx Validation Input validation errors
5xxx Auth Authentication/authorization errors
9xxx System Internal system errors

Checking Error Codes

ON ERROR RESUME NEXT

result = GET url

IF ERROR THEN
    SELECT CASE ERR
        CASE 1001
            TALK "Network timeout - please try again"
        CASE 1002
            TALK "Server not found"
        CASE 1003
            TALK "Connection refused"
        CASE 1404
            TALK "Resource not found"
        CASE 1500
            TALK "Server error - please try later"
        CASE ELSE
            TALK "Error " + ERR + ": " + ERROR MESSAGE
    END SELECT
END IF

Best Practices

Always Clear Errors When Continuing

ON ERROR RESUME NEXT

result = RISKY_OPERATION()
IF ERROR THEN
    ' Handle the error
    TALK "Operation failed"
    CLEAR ERROR  ' Clear before next operation
END IF

' Next operation won't see stale error
result2 = ANOTHER_OPERATION()

Disable Error Trapping When Done

ON ERROR RESUME NEXT

' Protected code section
result = RISKY_OPERATION()
IF ERROR THEN
    TALK "Handled error: " + ERROR MESSAGE
END IF

ON ERROR GOTO 0  ' Re-enable normal error behavior

' Errors here will halt execution as normal

Log Errors for Debugging

ON ERROR RESUME NEXT

result = COMPLEX_OPERATION()

IF ERROR THEN
    ' Log full details for debugging
    PRINT "ERROR at " + FORMAT(NOW(), "YYYY-MM-DD HH:mm:ss")
    PRINT "  Code: " + ERR
    PRINT "  Message: " + ERROR MESSAGE
    PRINT "  Context: processing " + current_item.id
    
    ' User-friendly message
    TALK "Something went wrong. Our team has been notified."
    CLEAR ERROR
END IF

Don't Ignore Errors Silently

' BAD - Errors are silently ignored
ON ERROR RESUME NEXT
data = GET url
TALK "Got data: " + data  ' May fail if GET failed

' GOOD - Check and handle errors
ON ERROR RESUME NEXT
data = GET url
IF ERROR THEN
    TALK "Could not fetch data"
    data = DEFAULT_DATA
END IF
TALK "Got data: " + data

Use Specific Error Checks

ON ERROR RESUME NEXT

result = DATABASE_OPERATION()

IF ERROR THEN
    error_msg = ERROR MESSAGE
    
    ' Handle specific errors differently
    IF INSTR(error_msg, "timeout") > 0 THEN
        WAIT 2
        result = DATABASE_OPERATION()  ' Retry
    ELSE IF INSTR(error_msg, "duplicate") > 0 THEN
        TALK "This record already exists"
    ELSE IF INSTR(error_msg, "permission") > 0 THEN
        TALK "You don't have permission for this action"
    ELSE
        TALK "Database error: " + error_msg
    END IF
END IF

Comparison with TRY...CATCH

For more complex error handling, you can use structured TRY...CATCH blocks:

' ON ERROR style (simpler)
ON ERROR RESUME NEXT
result = RISKY()
IF ERROR THEN
    TALK "Error: " + ERROR MESSAGE
END IF
ON ERROR GOTO 0

' TRY...CATCH style (more structured)
TRY
    result = RISKY()
CATCH e
    TALK "Error: " + e.message
END TRY

Use ON ERROR RESUME NEXT for:

  • Simple scripts with few error points
  • Quick prototyping
  • BASIC-familiar developers

Use TRY...CATCH for:

  • Complex error handling logic
  • Multiple specific catch blocks needed
  • Modern structured programming style

Implementation Notes

  • Implemented in Rust under src/basic/keywords/errors/on_error.rs
  • Error state is thread-local per script execution
  • Error trapping scope is global to the script (not block-scoped)
  • CLEAR ERROR resets both ERROR flag and ERROR MESSAGE
  • Maximum error message length: 4096 characters

  • THROW — Raise custom errors
  • ASSERT — Assert conditions
  • PRINT — Debug output for error logging
  • WAIT — Delay before retry

Summary

ON ERROR RESUME NEXT provides BASIC error handling for BASIC scripts, allowing graceful handling of errors without script termination. Always check ERROR after risky operations, use CLEAR ERROR before subsequent operations, and disable error trapping with ON ERROR GOTO 0 when protection is no longer needed. For user-facing errors, provide clear messages while logging technical details for debugging.