> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appsignal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exception handling

export const Compatibility = ({versions = [], label = "Available in"}) => {
  if (!Array.isArray(versions) || versions.length === 0) {
    return null;
  }
  const defaultPillStyle = {
    borderColor: "#d4d4d8",
    background: "#f4f4f5",
    color: "#3f3f46"
  };
  const pillStyles = {
    "AppSignal for Elixir": {
      background: "#f3e8ff",
      borderColor: "#d8b4fe",
      color: "#6b21a8"
    },
    "AppSignal for Front-end": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Go": {
      background: "#ccfbf1",
      borderColor: "#5eead4",
      color: "#115e59"
    },
    "AppSignal for JavaScript": {
      background: "#fef9c3",
      borderColor: "#fde047",
      color: "#854d0e"
    },
    "AppSignal for Node.js": {
      background: "#dcfce7",
      borderColor: "#86efac",
      color: "#166534"
    },
    "AppSignal for Python": {
      background: "#dbeafe",
      borderColor: "#93c5fd",
      color: "#1e40af"
    },
    "AppSignal for Ruby": {
      background: "#fee2e2",
      borderColor: "#fca5a5",
      color: "#991b1b"
    },
    "AppSignal for Rust": {
      background: "#ffedd5",
      borderColor: "#fdba74",
      color: "#9a3412"
    }
  };
  const getPillStyle = name => ({
    ...defaultPillStyle,
    ...pillStyles[name] || ({})
  });
  return <div className="not-prose my-4 rounded-lg border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm dark:border-white/10 dark:bg-white/5">
      <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
        <span className="font-semibold text-zinc-700 dark:text-zinc-200">
          {label}:
        </span>
        {versions.map((v, i) => <span key={`${v.name}-${v.version}-${i}`} className="inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-xs font-medium" style={getPillStyle(v.name)}>
            <span>{v.name}</span>
            <span className="opacity-70">
              {v.version}
              {v.exact ? "" : "+"}
            </span>
          </span>)}
      </div>
    </div>;
};

By default AppSignal tries to record as many exceptions (errors) as possible. With [our integrations](/ruby/integrations) for many frameworks and background job gems, not a lot of exceptions will slip past.

In most cases, errors not caused by bugs in your code occur when your app interacts with the real world. Bots might drop by and try to post forms automatically; outdated links might direct visitors to content that doesn't exist anymore, and so on.

To avoid these errors from being raised as problems in AppSignal, it's possible to add exception handling to your code or even let AppSignal entirely ignore specific errors.

## Ignore errors

The AppSignal configuration makes it possible to [ignore
errors](/guides/filter-data/ignore-errors). By providing a list of
specific errors AppSignal will not send alerts when these errors are raised.

## Exception handling

Simply ignoring an error will silence notifications, but could potentially hide
a bigger problem. For this reason we recommend you add exception handling with
`begin .. rescue` blocks to your application.

Using `begin .. rescue` you can catch specific exceptions and add an
alternative code path for when an exception occurs, such as rendering 404 pages
or providing the user with more detailed error messages about what went wrong.

<CodeGroup>
  ```ruby Ruby theme={null}
  begin
    user = Post.find(1)
  rescue RecordNotFound => e
    render :text => "Could not find post", :status => 404
  end
  ```
</CodeGroup>

There's a couple of scenarios that should be handled like this to provide
proper HTTP responses when resources don't exist or when a form submission
fails.

Read our primer on [Exception
handling](https://blog.appsignal.com/blog/2016/10/18/ruby-magic-exceptions-primer.html)
for more information on how it works and how to implement it correctly.

### Rails rescue\_from

Rails provides a mechanism to handle exceptions on controller-level. By
defining a `rescue_from` statement for a specific error it's possible to create
an alternative code path for when that exception is raised. Because this can be
defined on any controller level this makes it possible to add application-level
exception handling.

<CodeGroup>
  ```ruby Ruby theme={null}
  class ApplicationController < ActionController::Base
    rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found

    private

    def record_not_found
      render :text => "404: Resource not found", :status => 404
    end
  end
  ```
</CodeGroup>

More information about `rescue_from` can be found in the Rails guide about
[ActionController](https://guides.rubyonrails.org/action_controller_overview.html#rescue-from).

### Handle 404s

If a visitor hits a URL that cannot be handled by your routing or controller
Rack and other frameworks will raise an exception. It's usually a good idea to
handle these exceptions with a 404 response for your users.

In controllers where a `find` operation is performed based on a parameter from
an URL, it's recommended you handle `ActiveRecord::RecordNotFound` (or the
equivalent in your ORM of choice) to show a 404 response as well. This can hide
real bugs though, so it should be done with care.

### Handle invalid authenticity tokens

Rails has a mechanism that protects your forms from being filled out by
bots too easily. Any time a form is posted without a correct authenticity
token a `ActionController::InvalidAuthenticityToken` will be raised.

Sometimes legitimate users can run into these errors as well, so it's a good
idea to have a separate error page explaining what went wrong. We advise to
return this page with a 422 (Unprocessable Entity) response.

### Handle hacking attempts

You might get errors because bots or hackers are trying to exploit security
issues such as the notorious YAML exploit. Newer versions of Rails will throw a
`Hash::DisallowedType` when this happens. A `RangeError` is also often a result
of a hacking attempt. You could rescue these type of errors and return a 403
(Forbidden) response.

## Exception reporting helper methods

AppSignal provides a single interface to report exceptions with [`Appsignal.report_error`](#appsignalreport_error).

If your application is using Ruby gem version 3 or older, see the [legacy exception handling section](#legacy-exception-handling).

## Appsignal.report\_error

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "4.0.0" }]} />

Applications may have exception handling where they don't want to crash the Ruby process. By adding exception handling, the exception will no longer bubble up to the AppSignal instrumentation. AppSignal will not report these exceptions.

If you want to report the exception without crashing the application, use the `Appsignal.report_error` helper to report it to AppSignal from within the exception handling.

If an AppSignal Transaction is active, this helper will add the exception to the current Transaction. Applications can report multiple exceptions on one Transaction.

If no Transaction is active, this helper will create a new Transaction and report the exception on the newly created Transaction. AppSignal will always report the exception this way when using `Appsignal.report_error`.

<CodeGroup>
  ```ruby Ruby theme={null}
  begin
    # Some code that raises an exception
  rescue => error
    Appsignal.report_error(error)
    puts "Exiting. An error occurred: #{error}"
    exit 1
  end
  ```
</CodeGroup>

### Adding metadata

Customizing the metadata on the Transaction for the exception is possible by passing a block to the `Appsignal.report_error` helper. See our [Tagging](/guides/tagging) and [Data Customization](/guides/custom-data) guides for more information on what type of data can be added in this block.

The metadata set in the `Appsignal.report_error`'s block only applies to the exception given to the helper. Metadata set outside the `Appsignal.report_error` blocks is added to all exceptions if there's an active transaction.

<CodeGroup>
  ```ruby Ruby theme={null}
  begin
    # some code
  rescue => error
    Appsignal.report_error(error) do
      Appsignal.set_namespace("admin")
      Appsignal.set_action("MyCustomAction#perform")
      Appsignal.add_params(:param1 => "value1", :param2 => "value2")
      Appsignal.add_tags(:tag1 => "value1", :tag2 => "value2")
      Appsignal.add_custom_data(
        :i18n => {
          :locale => "en_GB",
          :default_locale => "en_US"
        }
      )
    end
  end
  ```
</CodeGroup>

### Reporting multiple exceptions

Multiple errors can be reported in one Transaction, like a Rails controller action handling an HTTP request or a Sidekiq background job.

A maximum of 10 errors can be set on one Transaction.

If multiple exceptions are reported in one Transaction, the metadata set in the `Appsignal.report_error`'s block only applies to the exception given to the helper. Metadata set outside of the `Appsignal.report_error` blocks is added to all exceptions.

<CodeGroup>
  ```ruby Ruby theme={null}
  def index
    # This tag is added to all exceptions
    Appsignal.add_tags(:some_tag_for_all_errors => true)

    begin
      raise "something went wrong"
    rescue => error
      # Report the first exception
      Appsignal.report_error(error) do
        # This tag is only added to the first exception
        Appsignal.add_tags(:some_tag => true)
      end
    end

    begin
      raise "something else went wrong"
    rescue => error
      # Report the second exception
      Appsignal.report_error(error) do
        # This tag is only added to the second exception
        Appsignal.add_tags(:other_tag => true)
      end
    end

    # This tag is added to all exceptions
    Appsignal.add_tags(:another_tag_for_all_errors => true)
  end
  ```
</CodeGroup>

### Report exceptions that crash a process

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "4.0.0" }]} />

By default, AppSignal will report exceptions that crash a Ruby process as long as AppSignal is started before the exception occurs.

<CodeGroup>
  ```ruby Ruby theme={null}
  # some_script.rb
  require "appsignal"

  Appsignal.start

  raise "I will crash the process!"
  ```
</CodeGroup>

To disable this functionality, set the [`enable_at_exit_reporter` config option](/ruby/configuration/options#option-enable_at_exit_reporter) to `false`.

### Short-lived Ruby processes

When reporting exceptions from [Ruby scripts](/ruby/instrumentation/background-jobs), [Rake tasks](/ruby/integrations/rake), Ruby processes that are short-lived, read the documentation on those pages on when to best call `Appsignal.stop` to ensure all exceptions are reported to AppSignal.

## Legacy exception handling

Read this section when using AppSignal for Ruby gem version 3 or older. For newer versions of our Ruby gem, use the [`Appsignal.report_error` helper](#appsignalreport_error).

AppSignal provides two exception reporting helper methods, which one you use will depend on the context of the error. The methods are:

* **[`set_error`](#appsignal-set_error):** The `set_error` helper sets the error on the currently active Transaction. If no transaction is active, no error is reported. Setting an error on the currently active transaction overrides any error previously set on the transaction.
* **[`send_error`](#appsignal-send_error):** Use `send_error` to report errors when no AppSignal transaction is active.

### Appsignal.set\_error

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "0.6.0" }]} />

There are scenarios where you have your own exception handling and don't want to crash the Ruby process. By adding your own exception handling the error is no longer bubbled up to the AppSignal integration and thus not recorded automatically.

If you still want to track the error you can use `Appsignal.set_error` to add the exception to the current AppSignal Transaction. The error will be recorded in AppSignal, but your process will not crash.

<CodeGroup>
  ```ruby Ruby theme={null}
  require "yaml"
  class SomeClass
    def call
      YAML.load(File.read("config.yml"))
    rescue SystemCallError => exception
      Appsignal.set_error(exception)
      puts "No config file found. Using defaults."
    end
  end
  ```
</CodeGroup>

The exception will be tracked by AppSignal like any other error, and it allows you to provide custom error handling and fallbacks.

Calling `set_error` only works when there is an AppSignal transaction active. Otherwise the error will be ignored. A transaction is active in most of our [automatically supported integrations](/ruby/integrations) and when using `Appsignal.monitor` or `Appsignal.monitor_transaction`. For more information on when to use `Appsignal.monitor_transaction`, see our [instrumentation for scripts and background jobs guide](/ruby/instrumentation/background-jobs).
See [`Appsignal.send_error`](#appsignal-send_error) for sending errors without an AppSignal transaction.

<CodeGroup>
  ```ruby Ruby theme={null}
  require "yaml"

  Appsignal.monitor :action => "My action" do
    begin
      YAML.load(File.read("config.yml"))
    rescue SystemCallError => exception
      Appsignal.set_error(exception)
      puts "No config file found. Using defaults."
    end
  end
  ```
</CodeGroup>

### Appsignal.send\_error

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "0.6.0" }]} />

AppSignal provides a mechanism to send errors to AppSignal without having to start a transaction. This is useful for tracking errors that occur in code that's not in a web or background job context, such as separate [Rake tasks](/ruby/integrations/rake) or [Ruby scripts](/ruby/instrumentation/background-jobs).

This is useful for instrumentation that doesn't automatically create AppSignal transactions to profile, such as our [integrations](/ruby/integrations).

You can use the `Appsignal.send_error` method to directly send an exception to AppSignal from any place in your code without starting an AppSignal transaction with `Appsignal.monitor` first.

<CodeGroup>
  ```ruby Ruby theme={null}
  begin
    # some code
  rescue => e
    Appsignal.send_error(e)
  end
  ```
</CodeGroup>

#### Adding metadata {/* id: appsignal-send_error-adding-metadata */}

<Compatibility versions={[{ name: "AppSignal for Ruby", version: "2.9.0" }]} />

In AppSignal for Ruby gem 2.9 and newer an additional block can be passed to the `Appsignal.send_error` method to add more metadata to the error transaction. This includes metadata such as the action name and parameters. Older versions of the Ruby gem will not allow additional metadata to be set.

<CodeGroup>
  ```ruby Ruby theme={null}
  begin
    # some code
  rescue => e
    Appsignal.send_error(e) do |transaction|
      transaction.set_action("my_action")
      transaction.set_namespace("my_namespace")
      transaction.params = { :time => Time.now.utc }
    end
  end
  ```
</CodeGroup>

### Appsignal.listen\_for\_error

<Warning>
  This helper is removed in Ruby gem version 4. Instead, use a Ruby `rescue`
  block with the [`Appsignal.report_error` helper](#appsignalreport_error).
</Warning>

An alternative way to track errors with AppSignal is to wrap code that might
raise an exception in a `listen_for_error` block. If an exception gets raised
within that block it's automatically tracked by AppSignal and re-raised. This
allows the application and frameworks to handle exception as normal.

<CodeGroup>
  ```ruby Ruby theme={null}
  require "rake"
  require "appsignal"

  task :fail do
    Appsignal.listen_for_error do
      raise "I am an exception in a Rake task"
    end
  end
  ```
</CodeGroup>
