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:
SlashCommandChecksFailedContextMenuChecksFailed
What the prototype code fix handles
The current code fix is intentionally conservative.
It offers an automatic rewrite for handlers that:
- subscribe to
ApplicationCommandsExtension.SlashCommandErroredorApplicationCommandsExtension.ContextMenuErrored - immediately guard on
args.Exception is SlashExecutionChecksFailedException ...orargs.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
FailedCheckspredicate such asfailed.FailedChecks.Any(...)on the supported guard - only use
args.Contextand optionalfailed.FailedChecksinside 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
*ChecksFailedsubscription 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.