Compile-time errors are found before a program runs.

Runtime errors happen while the program is running.

The difference is about when the problem is detected, not always where the bug was written.

Compile-time errors

Compile-time errors are caught by a Compiler, parser, type checker, linter, or build tool before execution.

Common examples:

  • Syntax errors: the code does not follow the language grammar, like a missing bracket or invalid keyword placement.
  • Type errors: a value is used in a way that does not match its type, especially in a Statically Typed Programming Language.
  • Name or reference errors: the compiler cannot find a variable, function, module, or symbol.
  • Build errors: the program cannot be compiled or packaged because of missing dependencies, incompatible versions, or invalid configuration.

Compile-time errors are usually easier to catch early because the program does not need a specific user action or production state to expose them.

Runtime errors

Runtime errors occur after the program starts executing.

Common examples:

  • Exceptions: the program hits an exceptional condition, such as division by zero, file-not-found, or invalid input.
  • Null or undefined access: the program tries to use a missing value as if it exists.
  • Resource errors: the program runs out of memory, cannot open a network connection, or loses access to a file.
  • Concurrency errors: timing-sensitive bugs such as race conditions and deadlocks.
  • Process failures: the program exits with a non-zero status or is terminated by a signal.

Runtime errors can be harder to reproduce because they may depend on input, environment, timing, data, or external systems.

Why handle errors

Error handling gives the program a deliberate response to failure instead of letting every problem become a crash, corrupt result, or unclear non-zero exit.

Programs handle errors to:

  • Return a useful message to a user or caller
  • Preserve data integrity
  • Clean up resources such as files, locks, sockets, or database transactions
  • Retry transient failures, such as network timeouts
  • Choose a fallback path when a dependency is unavailable
  • Add context so the failure can be debugged later
  • Exit with a meaningful non-zero status when the program cannot continue

Not every error should be recovered from. Some failures should stop the program because continuing would be unsafe or misleading.

Go and Python

Go and Python both have runtime errors, but they usually express recoverable errors differently.

In Go, ordinary errors are usually explicit return values:

value, err := doThing()
if err != nil {
    return err
}

This makes failure part of the normal control flow. Go also has panic, which is closer to an unrecoverable runtime failure or programmer mistake, although recover can intercept it in limited cases.

In Python, recoverable runtime errors are usually represented as exceptions:

try:
    value = do_thing()
except ValueError as err:
    handle_error(err)

An unhandled Python exception prints a traceback and exits the process with a non-zero status.

Exit status and signals

A non-zero exit status is how a process reports failure to the operating system or caller.

It usually means the program detected an error and chose to exit unsuccessfully. The underlying cause may be a runtime error, invalid input, failed configuration, missing permissions, or a failed dependency.

A signal termination means the process was interrupted by the operating system, shell, user, or another process.

Examples:

  • SIGABRT: the program aborted, often because it deliberately called abort() or failed an internal assertion.
  • SIGSEGV: the program accessed invalid memory.
  • SIGKILL: the process was forcibly killed and could not handle the signal.
  • SIGTERM: the process was asked to terminate.

Signals are runtime failures from the point of view of the process, but not all of them mean the source code has a bug. For example, SIGTERM may be part of normal service shutdown.

Segmentation faults

A segmentation fault is a runtime failure where a program tries to access memory it is not allowed to access.

On Unix-like systems this usually terminates the process with SIGSEGV.

Common causes:

  • Dereferencing a null or invalid pointer
  • Reading or writing memory after it has been freed
  • Writing past the end of an array or buffer
  • Using stack memory after the stack frame has returned

Segfaults are common in languages with manual memory management, such as C Language and C++.

Logical errors

Logical errors happen when the program runs, but does the wrong thing.

The code may be syntactically valid and may not crash, but the algorithm, condition, calculation, or assumption is wrong.

Examples:

  • Using > when the correct condition is >=
  • Sorting by the wrong field
  • Charging the wrong amount because the formula is incorrect
  • Returning the first match when the requirement needs the best match

Logical errors are often found through unit tests, code review, debugging, or user reports.

Semantic errors

Semantic errors are errors in meaning.

Some semantic errors are caught at compile time, such as using a string where an integer is required. Others become runtime or logical errors, such as calling the right function with the wrong business meaning.