Skip to content

Runtime Errors

This guide covers common runtime errors in programming, their causes, and how to prevent and handle them across different programming languages.

🎯 What Are Runtime Errors?

Runtime errors occur during program execution, causing the program to crash, behave unexpectedly, or produce incorrect results.

Characteristics of Runtime Errors

  • Code compiles successfully
  • Errors occur during execution
  • Often cause program crashes or exceptions
  • Can be handled with error management techniques

🚨 Common Types of Runtime Errors

1. Null Pointer/Reference Errors

Attempting to access methods or fields of null objects.

Problem Examples

// Java: NullPointerException
String name = null;
int length = name.length();  // Throws NullPointerException

// Bad: No null check
public void processUser(User user) {
    System.out.println(user.getName());  // NPE if user is null
}
# Python: AttributeError
name = None
print(name.upper())  # AttributeError: 'NoneType' object has no attribute 'upper'

# Bad: No null check
def process_user(user):
    print(user.name)  # AttributeError if user is None
// C: Segmentation fault
int* ptr = NULL;
*ptr = 42;  // Segmentation fault

// Bad: No null check
void process_user(User* user) {
    printf("%s\n", user->name);  // Segmentation fault if user is NULL
}

Solutions

// Good: Null check
public void processUser(User user) {
    if (user != null) {
        System.out.println(user.getName());
    } else {
        System.out.println("User is null");
    }
}

// Better: Use Optional (Java 8+)
public void processUser(User user) {
    Optional.ofNullable(user)
        .map(User::getName)
        .ifPresentOrElse(
            System.out::println,
            () -> System.out.println("User is null")
        );
}
# Good: Null check
def process_user(user):
    if user is not None:
        print(user.name)
    else:
        print("User is None")

# Better: Use duck typing with hasattr
def process_user(user):
    if hasattr(user, 'name'):
        print(user.name)
    else:
        print("Invalid user object")
// Good: Null check
void process_user(User* user) {
    if (user != NULL) {
        printf("%s\n", user->name);
    } else {
        printf("User is NULL\n");
    }
}

2. Array Index Out of Bounds

Accessing array elements outside valid index range.

Problem Examples

// Java: ArrayIndexOutOfBoundsException
int[] numbers = {1, 2, 3};
int value = numbers[3];  // Index 3 doesn't exist (valid: 0,1,2)

// Bad: Loop with incorrect bounds
for (int i = 0; i <= numbers.length; i++) {
    System.out.println(numbers[i]);  // Exception when i = 3
}
# Python: IndexError
numbers = [1, 2, 3]
value = numbers[3]  # IndexError: list index out of range

# Bad: Loop with incorrect bounds
for i in range(len(numbers) + 1):
    print(numbers[i])  # IndexError when i = 3
// C: Undefined behavior (may crash or produce garbage)
int numbers[3] = {1, 2, 3};
int value = numbers[3];  // Out of bounds access

// Bad: Buffer overflow
char buffer[10];
strcpy(buffer, "This string is too long");  // Buffer overflow

Solutions

// Good: Bounds checking
public int getSafeValue(int[] arr, int index) {
    if (index >= 0 && index < arr.length) {
        return arr[index];
    } else {
        throw new IllegalArgumentException("Index out of bounds");
    }
}

// Better: Use enhanced for-loop
for (int value : numbers) {
    System.out.println(value);  // No index access needed
}
# Good: Bounds checking
def get_safe_value(arr, index):
    if 0 <= index < len(arr):
        return arr[index]
    else:
        raise IndexError("Index out of bounds")

# Better: Use try-except
try:
    value = numbers[index]
except IndexError:
    print("Index out of bounds")
    value = None
// Good: Bounds checking
int get_safe_value(int* arr, int size, int index) {
    if (index >= 0 && index < size) {
        return arr[index];
    } else {
        fprintf(stderr, "Index out of bounds\n");
        exit(1);
    }
}

// Better: Use safe string functions
char buffer[10];
strncpy(buffer, "This string is too long", sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';  // Ensure null termination

3. Arithmetic Errors

Division by Zero

Attempting to divide by zero.

Overflow Issues

Integer overflow occurs when an arithmetic operation attempts to create a numeric value that is outside of the range that can be represented with a given number of bits. For example, adding two large positive numbers might result in a negative number if the result exceeds the maximum value of a signed integer.

Problem Examples

// Java: ArithmeticException
int result = 10 / 0;  // Throws ArithmeticException

double result = 10.0 / 0.0;  // Returns Infinity
# Python: ZeroDivisionError
result = 10 / 0  # ZeroDivisionError: division by zero

result = 10.0 / 0.0  # Returns inf (infinity)
// C: Undefined behavior (may crash)
int result = 10 / 0;  // Floating point exception

Solutions

// Good: Check before division
public double safeDivide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Cannot divide by zero");
    }
    return (double) a / b;
}

// Better: Handle gracefully
public Optional<Double> safeDivide(int a, int b) {
    if (b == 0) {
        return Optional.empty();
    }
    return Optional.of((double) a / b);
}
# Good: Check before division
def safe_divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# Better: Handle gracefully
def safe_divide_or_none(a, b):
    if b == 0:
        return None
    return a / b
// Good: Check before division
double safe_divide(int a, int b) {
    if (b == 0) {
        fprintf(stderr, "Cannot divide by zero\n");
        return 0.0;
    }
    return (double)a / b;
}

4. Type Conversion Errors

Invalid type casting or conversion.

Problem Examples

// Java: ClassCastException
Object obj = "hello";
Integer num = (Integer) obj;  // ClassCastException

// Bad: Unsafe casting
List<String> list = (List<String>) unknownObject;  // May fail
# Python: ValueError or TypeError
num = int("hello")  # ValueError: invalid literal for int()

# Bad: Unsafe conversion
value = "123.45"
num = int(value)  # ValueError: invalid literal for int() with base 10
// C: Undefined behavior
int* ptr = (int*)malloc(sizeof(char) * 10);
*ptr = 42;  // May cause issues due to wrong type

Solutions

// Good: Safe casting with instanceof
public Integer safeCastToInteger(Object obj) {
    if (obj instanceof Integer) {
        return (Integer) obj;
    }
    return null;
}

// Better: Use generics
public <T> T safeCast(Object obj, Class<T> type) {
    if (type.isInstance(obj)) {
        return type.cast(obj);
    }
    return null;
}
# Good: Safe conversion with try-except
def safe_int_conversion(value):
    try:
        return int(value)
    except ValueError:
        return None

# Better: Check type first
def safe_int_conversion_better(value):
    if isinstance(value, (int, float)):
        return int(value)
    elif isinstance(value, str) and value.isdigit():
        return int(value)
    return None
// Good: Proper type usage
char* ptr = (char*)malloc(sizeof(char) * 10);
if (ptr != NULL) {
    strcpy(ptr, "hello");
    printf("%s\n", ptr);
    free(ptr);
}

5. Memory Management Errors

Memory leaks, double free, or use-after-free.

Problem Examples

// C: Memory leak
void memory_leak() {
    int* ptr = malloc(sizeof(int) * 100);
    *ptr = 42;
    // Forgot to free(ptr)!
}

// Double free
void double_free() {
    int* ptr = malloc(sizeof(int));
    free(ptr);
    free(ptr);  // Double free error
}

// Use after free
void use_after_free() {
    int* ptr = malloc(sizeof(int));
    free(ptr);
    *ptr = 42;  // Use after free
}

Solutions

// Good: Proper memory management
void proper_memory_management() {
    int* ptr = malloc(sizeof(int) * 100);
    if (ptr == NULL) {
        return;  // Handle allocation failure
    }

    *ptr = 42;
    printf("%d\n", *ptr);
    free(ptr);  // Always free allocated memory
    ptr = NULL;  // Avoid dangling pointers
}

// Better: Use helper functions
void safe_free(void** ptr) {
    if (ptr != NULL && *ptr != NULL) {
        free(*ptr);
        *ptr = NULL;
    }
}

void use_safe_free() {
    int* ptr = malloc(sizeof(int));
    safe_free((void**)&ptr);
    safe_free((void**)&ptr);  // Safe to call again
}

🛠️ Error Handling Strategies

Exception Handling

// Java: Try-catch-finally
public void readFile(String filename) {
    BufferedReader reader = null;
    try {
        reader = new BufferedReader(new FileReader(filename));
        String line = reader.readLine();
        System.out.println(line);
    } catch (FileNotFoundException e) {
        System.err.println("File not found: " + filename);
    } catch (IOException e) {
        System.err.println("Error reading file: " + e.getMessage());
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                System.err.println("Error closing file: " + e.getMessage());
            }
        }
    }
}
# Python: Try-except-else-finally
def read_file(filename):
    try:
        with open(filename, 'r') as file:
            content = file.read()
    except FileNotFoundError:
        print(f"File not found: {filename}")
        return None
    except IOError as e:
        print(f"Error reading file: {e}")
        return None
    else:
        return content
    finally:
        print("File operation completed")

Resource Management

// Java: Try-with-resources
public void readFile(String filename) {
    try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
        String line = reader.readLine();
        System.out.println(line);
    } catch (IOException e) {
        System.err.println("Error reading file: " + e.getMessage());
    }
}
# Python: Context managers
def read_file(filename):
    try:
        with open(filename, 'r') as file:
            return file.read()
    except IOError as e:
        print(f"Error reading file: {e}")
        return None

🔍 Debugging Runtime Errors

Logging and Debugging

// Java: Logging
import java.util.logging.Logger;

public class DebugExample {
    private static final Logger logger = Logger.getLogger(DebugExample.class.getName());

    public void processArray(int[] arr, int index) {
        logger.info("Processing array of length " + arr.length + " at index " + index);

        if (index < 0 || index >= arr.length) {
            logger.severe("Index out of bounds: " + index);
            throw new IllegalArgumentException("Index out of bounds");
        }

        int value = arr[index];
        logger.info("Retrieved value: " + value);
    }
}
# Python: Logging
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def process_array(arr, index):
    logger.info(f"Processing array of length {len(arr)} at index {index}")

    if index < 0 or index >= len(arr):
        logger.error(f"Index out of bounds: {index}")
        raise IndexError("Index out of bounds")

    value = arr[index]
    logger.info(f"Retrieved value: {value}")
    return value

Unit Testing

// Java: JUnit test for runtime errors
import org.junit.Test;
import static org.junit.Assert.*;

public class ArrayProcessorTest {

    @Test(expected = IllegalArgumentException.class)
    public void testIndexOutOfBounds() {
        ArrayProcessor processor = new ArrayProcessor();
        int[] arr = {1, 2, 3};
        processor.processArray(arr, 5);  // Should throw exception
    }

    @Test
    public void testValidIndex() {
        ArrayProcessor processor = new ArrayProcessor();
        int[] arr = {1, 2, 3};
        int result = processor.processArray(arr, 1);
        assertEquals(2, result);
    }
}
# Python: pytest for runtime errors
import pytest

def test_index_out_of_bounds():
    processor = ArrayProcessor()
    arr = [1, 2, 3]

    with pytest.raises(IndexError):
        processor.process_array(arr, 5)

def test_valid_index():
    processor = ArrayProcessor()
    arr = [1, 2, 3]
    result = processor.process_array(arr, 1)
    assert result == 2

🔗 Language-Specific Runtime Errors