Table of Contents

DisCatSharp Analyzer Rule DCS2101

This rule identifies legacy application-command error handlers that still handle failed checks through SlashCommandErrored or ContextMenuErrored.

The rule is reported as an error because leaving these handlers on the legacy errored events can break consumer behavior once checks failures stop flowing through those events.

The modern application-command flow exposes dedicated checks-failed events instead:

  • SlashCommandChecksFailed
  • ContextMenuChecksFailed

What the prototype code fix handles

The current code fix is intentionally conservative.

It offers an automatic rewrite for handlers that:

  • subscribe to ApplicationCommandsExtension.SlashCommandErrored or ApplicationCommandsExtension.ContextMenuErrored
  • immediately guard on args.Exception is SlashExecutionChecksFailedException ... or args.Exception is ContextMenuExecutionChecksFailedException ...
  • or use an early-return form such as if (args.Exception is not SlashExecutionChecksFailedException ...) return;
  • or use a top-level switch (args.Exception) case for the checks-failed exception type
  • or add an extra FailedChecks predicate such as failed.FailedChecks.Any(...) on the supported guard
  • only use args.Context and optional failed.FailedChecks inside the guarded logic

When that shape is detected, the fixer can:

  • rewrite the entire handler to the dedicated checks-failed event when the whole handler only exists for check failures
  • extract the checks-failed branch into a new *ChecksFailed subscription when the legacy handler also contains unrelated errored-event logic

The code action title reflects which path it is taking:

  • Rewrite handler to '...ChecksFailed'
  • Extract checks-failed branch to '...ChecksFailed'

In both cases, the fixer rewrites failed.FailedChecks access to args.FailedChecks. For supported wrapper shapes, that extraction can also preserve outer statements such as args.Handled = true and nested Task.Run(...) blocks. When the original guard also filters a subset of failed checks, the migrated handler keeps that subset filter by rewriting it to use args.FailedChecks.

What it reports without rewriting

The rule can still report more complex handlers, for example when they:

  • mix check-failure handling with unrelated error handling
  • require a manual migration because the handler shape cannot be split safely yet

Those cases still need attention because the checks-failed logic belongs on the dedicated event.

What it does not rewrite

The prototype still leaves more complex handlers alone when they:

  • depend on other exception members
  • use unsupported control-flow shapes beyond the currently supported top-level switch (args.Exception) case migration
  • cannot be split into a dedicated checks-failed handler without risking behavior changes

Those cases need either a more advanced migration fixer or a manual migration.