Skip to content

DeprecatedChecksConfig false-positives on every :disabled entry #1302

Description

@johnnyt

On master, Credo.Check.Design.DeprecatedChecksConfig reports one false positive for every entry in the :disabled list of a config that is already in the new, recommended format. The output of mix credo gen.config therefore fails the check that ships alongside it.

Environment

  • credo master @ 89457a1608a5b027e508d500f53748aef99d4f1d (reports 1.8.0-dev)
  • Elixir 1.18.3 / OTP 27, macOS
  • Clean on 1.7.19 (see the control below), so this looks like a regression from the unreleased DeprecatedChecksConfig work (e5ed4af2, 2026-04-28).

Reproduction

mix new repro && cd repro
# add to deps: {:credo, github: "rrrene/credo", branch: "master", only: [:dev, :test], runtime: false}
mix deps.get
mix credo gen.config     # stock config, unedited
mix credo --strict

Actual

5 mods/funs, found 38 software design suggestions.

All 38 are the same shape, one per :disabled entry:

┃ [D] → Using `false` for deactivating check `Credo.Check.Design.DuplicatedCode`
┃       in Credo's config is deprecated, move them to `:disabled` instead.
┃       .credo.exs #(config)

The advice cannot be followed: those checks are already in :disabled, which is what the message asks for. mix credo --strict exits 2, so this fails a build that gates on credo.

Expected

No issues. The generated config is in the map form with :enabled / :disabled keys that this check exists to encourage.

Control on 1.7.19

Same project, same steps, only the dep changed to {:credo, "~> 1.7"}:

5 mods/funs, found no issues.

Cause

ConfigFile.merge_checks/2 folds the :disabled list into :enabled as {check, false} pairs:

https://github.com/rrrene/credo/blob/master/lib/credo/config_file.ex#L391-L395

disabled = disable_check_tuples(checks_other[:disabled])

%{
  enabled: checks_other_enabled |> normalize_check_tuples() |> Keyword.merge(disabled),
  disabled: checks_other[:disabled] || []
}

with

defp disable_check_tuple({name}), do: {name, false}
defp disable_check_tuple({name, _params}), do: {name, false}

DeprecatedChecksConfig then scans enabled ++ disabled from the validated config and flags any {check, false} it finds:

https://github.com/rrrene/credo/blob/master/lib/credo/check/design/deprecated_checks_config.ex#L62-L72

So it is matching credo's own internal normalization, not anything the user wrote. Every :disabled entry produces exactly one finding, which is why the count tracks the size of that list.

The sibling merge_checks/2 clause just below uses Keyword.drop/2 rather than merging false values, and does not have the problem — that may be the intended shape for both.

Note that the check reads the post-merge "credo.validated_config" assign, so it cannot distinguish the deprecated user-written {Check, false} form from the internal one. Detecting the deprecated format probably has to happen against the raw config file, before normalization.

Workaround

Move Credo.Check.Design.DeprecatedChecksConfig itself to :disabled, or keep the :disabled list empty and rely on omission. Both lose something worth having, which is why I would rather report it than sit on the workaround.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions