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

# Elixir

> Learn about the Elixir anti-patterns detected by CodeAnt AI.

<AccordionGroup>
  <Accordion title="Use consistent exception names">
    Exception modules should consistently use the conventional `Error` suffix.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      defmodule PaymentException, do: defexception([:message])
      defmodule RefundError, do: defexception([:message])
      ```

      ```elixir Fix theme={"system"}
      defmodule PaymentError, do: defexception([:message])
      defmodule RefundError, do: defexception([:message])
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use consistent line endings">
    Mixing Unix (`LF`) and Windows (`CRLF`) line endings creates noisy diffs and inconsistent formatting.

    <CodeGroup>
      ```text Bad theme={"system"}
      lib/user.ex     LF
      lib/account.ex  CRLF
      ```

      ```text Fix theme={"system"}
      lib/user.ex     LF
      lib/account.ex  LF
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use consistent parameter pattern matching">
    When naming a matched parameter, place the variable consistently before or after the pattern.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def parse({:ok, value} = result), do: {result, value}
      def save(result = {:ok, value}), do: {result, value}
      ```

      ```elixir Fix theme={"system"}
      def parse({:ok, value} = result), do: {result, value}
      def save({:ok, value} = result), do: {result, value}
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use consistent spacing around operators">
    Consistent whitespace around operators makes expressions easier to scan.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      total=price*quantity
      ```

      ```elixir Fix theme={"system"}
      total = price * quantity
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use consistent spacing inside parentheses">
    Do not add unnecessary spaces immediately inside parentheses.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      calculate( price, quantity )
      ```

      ```elixir Fix theme={"system"}
      calculate(price, quantity)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use consistent indentation">
    Use spaces consistently instead of mixing tab- and space-indented lines.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def run do
        prepare() # tab-indented in the source file
        execute() # space-indented in the source file
      end
      ```

      ```elixir Fix theme={"system"}
      def run do
        prepare()
        execute()
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Alias nested modules">
    Alias nested dependencies so a module's external dependencies are visible at a glance.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def search(query) do
        MyApp.External.SearchClient.run(query)
      end
      ```

      ```elixir Fix theme={"system"}
      alias MyApp.External.SearchClient

      def search(query), do: SearchClient.run(query)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Resolve FIXME tags">
    `FIXME` tags identify known broken or unsafe behavior that should be corrected.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      # FIXME: accept every role until authorization is implemented
      def authorized?(_user), do: true
      ```

      ```elixir Fix theme={"system"}
      def authorized?(%User{role: role}), do: role in [:admin, :editor]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Resolve TODO tags">
    Replace incomplete `TODO` placeholders with the intended implementation.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      # TODO: persist this user
      def create_user(attrs), do: {:ok, attrs}
      ```

      ```elixir Fix theme={"system"}
      def create_user(attrs), do: Repo.insert(User.changeset(%User{}, attrs))
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Order aliases consistently">
    Keep aliases alphabetically ordered so dependencies are easy to find.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      alias MyApp.Users
      alias MyApp.Accounts
      ```

      ```elixir Fix theme={"system"}
      alias MyApp.Accounts
      alias MyApp.Users
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use conventional function names">
    Elixir function names should use lowercase `snake_case` and may end in `?` or `!`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def LoadUser(user_id), do: Repo.get(User, user_id)
      ```

      ```elixir Fix theme={"system"}
      def load_user(user_id), do: Repo.get(User, user_id)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Make large numbers readable">
    Add underscore separators to large numeric literals.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      upload_limit = 10000000
      ```

      ```elixir Fix theme={"system"}
      upload_limit = 10_000_000
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Keep lines within the maximum length">
    Split long expressions into named values or multiple lines.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Logger.info("created user #{user.id} for organization #{organization.id} with permissions #{inspect(permissions)}")
      ```

      ```elixir Fix theme={"system"}
      metadata = "organization #{organization.id}, permissions #{inspect(permissions)}"
      Logger.info("created user #{user.id} for #{metadata}")
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use conventional module attribute names">
    Module attributes should use lowercase `snake_case`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      @RetryLimit 3
      ```

      ```elixir Fix theme={"system"}
      @retry_limit 3
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Document modules">
    Public modules should explain their purpose with `@moduledoc`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      defmodule MyApp.Invoice do
        def total(invoice), do: invoice.subtotal + invoice.tax
      end
      ```

      ```elixir Fix theme={"system"}
      defmodule MyApp.Invoice do
        @moduledoc "Calculates invoice totals."
        def total(invoice), do: invoice.subtotal + invoice.tax
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use conventional module names">
    Module names should use `CamelCase` without underscores.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      defmodule MyApp.User_Profile do
      end
      ```

      ```elixir Fix theme={"system"}
      defmodule MyApp.UserProfile do
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid unnecessary parentheses in conditions">
    Elixir conditions do not need surrounding parentheses.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      if (user.active?) do
        send_welcome(user)
      end
      ```

      ```elixir Fix theme={"system"}
      if user.active? do
        send_welcome(user)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid parentheses on zero-arity definitions">
    Zero-arity function definitions conventionally omit parentheses.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def current_time(), do: DateTime.utc_now()
      ```

      ```elixir Fix theme={"system"}
      def current_time, do: DateTime.utc_now()
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid piping into anonymous functions">
    Assign or invoke an anonymous function directly instead of hiding the call in a pipeline.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      value
      |> (fn item -> normalize(item) end).()
      ```

      ```elixir Fix theme={"system"}
      normalizer = fn item -> normalize(item) end
      normalizer.(value)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use conventional predicate function names">
    Functions returning booleans should end in `?`; reserve `is_` names for guards.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def is_active(user), do: user.status == :active
      ```

      ```elixir Fix theme={"system"}
      def active?(user), do: user.status == :active
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prefer implicit try">
    Function-level `rescue`, `catch`, and `after` clauses are clearer without a redundant `try`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def load(path) do
        try do
          File.read!(path)
        rescue
          File.Error -> :error
        end
      end
      ```

      ```elixir Fix theme={"system"}
      def load(path) do
        File.read!(path)
      rescue
        File.Error -> :error
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove redundant blank lines">
    Use a single blank line to separate related sections.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def first, do: :ok


      def second, do: :ok
      ```

      ```elixir Fix theme={"system"}
      def first, do: :ok

      def second, do: :ok
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid semicolons">
    Put expressions on separate lines instead of separating them with semicolons.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      user = load_user(id); notify(user)
      ```

      ```elixir Fix theme={"system"}
      user = load_user(id)
      notify(user)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Add spaces after commas">
    Commas should be followed by a space.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      create_user(name,email,role)
      ```

      ```elixir Fix theme={"system"}
      create_user(name, email, role)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use string sigils when they improve readability">
    Sigils remove distracting escape characters from strings containing many quotes.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      html = "<a href=\"/docs\" target=\"_blank\">Docs</a>"
      ```

      ```elixir Fix theme={"system"}
      html = ~S(<a href="/docs" target="_blank">Docs</a>)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="End files with a trailing newline">
    End every source file with exactly one newline for portable tooling and clean diffs.

    <CodeGroup>
      ```text Bad theme={"system"}
      defmodule MyApp.User do
      end[EOF]
      ```

      ```text Fix theme={"system"}
      defmodule MyApp.User do
      end
      [newline][EOF]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove trailing whitespace">
    Remove invisible spaces and tabs at the end of source lines.

    <CodeGroup>
      ```text Bad theme={"system"}
      name = "Ada"[four trailing spaces]
      ```

      ```text Fix theme={"system"}
      name = "Ada"
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid unnecessary alias expansion">
    Use the alias directly instead of repeating its namespace.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      alias MyApp.Accounts
      MyApp.Accounts.create_user(attrs)
      ```

      ```elixir Fix theme={"system"}
      alias MyApp.Accounts
      Accounts.create_user(attrs)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use conventional variable names">
    Variables should use lowercase `snake_case`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      UserName = "Ada"
      ```

      ```elixir Fix theme={"system"}
      user_name = "Ada"
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use case for a single-clause with">
    A `with` containing one match and an `else` branch is clearer as a `case`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      with {:ok, user} <- Accounts.fetch_user(id) do
        user
      else
        {:error, reason} -> raise "failed: #{inspect(reason)}"
      end
      ```

      ```elixir Fix theme={"system"}
      case Accounts.fetch_user(id) do
        {:ok, user} -> user
        {:error, reason} -> raise "failed: #{inspect(reason)}"
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prefer direct function calls over apply">
    When the target and argument count are known, call the function directly.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      apply(String, :upcase, [name])
      ```

      ```elixir Fix theme={"system"}
      String.upcase(name)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Simplify short cond expressions">
    A `cond` with one condition plus a fallback should be an `if`/`else`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      cond do
        score >= 60 -> :pass
        true -> :fail
      end
      ```

      ```elixir Fix theme={"system"}
      if score >= 60 do
        :pass
      else
        :fail
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Reduce cyclomatic complexity">
    Too many branches make functions difficult to understand and test. Extract named decisions.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def price(order) do
        cond do
          order.vip? and order.total > 100 -> order.total * 0.8
          order.vip? -> order.total * 0.9
          order.total > 100 -> order.total * 0.95
          true -> order.total
        end
      end
      ```

      ```elixir Fix theme={"system"}
      def price(order), do: order.total * discount(order)
      defp discount(%{vip?: true, total: total}) when total > 100, do: 0.8
      defp discount(%{vip?: true}), do: 0.9
      defp discount(%{total: total}) when total > 100, do: 0.95
      defp discount(_order), do: 1.0
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Enum.count with a predicate">
    Count matching elements in one pass with `Enum.count/2`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      users
      |> Enum.filter(& &1.active?)
      |> Enum.count()
      ```

      ```elixir Fix theme={"system"}
      Enum.count(users, & &1.active?)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Combine consecutive filters">
    Combining predicates avoids traversing an intermediate collection.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      users
      |> Enum.filter(& &1.active?)
      |> Enum.filter(&(&1.age >= 18))
      ```

      ```elixir Fix theme={"system"}
      Enum.filter(users, fn user ->
        user.active? and user.age >= 18
      end)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Limit function arity">
    Too many parameters make calls error-prone. Group related values into a struct or map.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def create_user(name, email, role, team, locale, timezone) do
        # ...
      end
      ```

      ```elixir Fix theme={"system"}
      def create_user(%UserParams{} = params) do
        # ...
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Keep quote blocks concise">
    Large quoted AST blocks should delegate to smaller macros or helper functions.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      quote do
        def start, do: :ok
        def stop, do: :ok
        def restart, do: :ok
        def status, do: :running
      end
      ```

      ```elixir Fix theme={"system"}
      quote do
        unquote(lifecycle_functions())
        unquote(status_function())
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Enum.map_join">
    Map and join in one traversal with `Enum.map_join/3`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      users
      |> Enum.map(& &1.name)
      |> Enum.join(", ")
      ```

      ```elixir Fix theme={"system"}
      Enum.map_join(users, ", ", & &1.name)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid matches in conditions">
    Use `case` when control flow depends on the shape of a value.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      if {:ok, contents} = File.read(path) do
        process(contents)
      end
      ```

      ```elixir Fix theme={"system"}
      case File.read(path) do
        {:ok, contents} -> process(contents)
        {:error, reason} -> handle_error(reason)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid negated conditions in unless">
    A negated `unless` condition is a double negative.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      unless not user.active? do
        notify(user)
      end
      ```

      ```elixir Fix theme={"system"}
      if user.active? do
        notify(user)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Invert negated conditions with else">
    Put the positive condition first and swap the branches.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      if not authorized?(user) do
        {:error, :forbidden}
      else
        perform_action(user)
      end
      ```

      ```elixir Fix theme={"system"}
      if authorized?(user) do
        perform_action(user)
      else
        {:error, :forbidden}
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Reduce control-flow nesting">
    Extract nested decisions into functions or use pattern matching and early returns.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      if user do
        if user.active? do
          if user.admin?, do: grant_access(user)
        end
      end
      ```

      ```elixir Fix theme={"system"}
      def grant_if_allowed(%User{active?: true, admin?: true} = user),
        do: grant_access(user)

      def grant_if_allowed(_user), do: {:error, :forbidden}
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove redundant with clause results">
    Do not match the final result only to return the identical value.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      with {:ok, user} <- Accounts.fetch_user(id),
           {:ok, result} <- authorize(user) do
        {:ok, result}
      end
      ```

      ```elixir Fix theme={"system"}
      with {:ok, user} <- Accounts.fetch_user(id) do
        authorize(user)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Combine consecutive rejects">
    Combine predicates to avoid traversing an intermediate collection.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      users
      |> Enum.reject(& &1.disabled?)
      |> Enum.reject(& &1.deleted?)
      ```

      ```elixir Fix theme={"system"}
      Enum.reject(users, fn user ->
        user.disabled? or user.deleted?
      end)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid unless with else">
    An `unless` with an `else` branch is easier to understand as an `if`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      unless user.active? do
        deactivate_session(user)
      else
        refresh_session(user)
      end
      ```

      ```elixir Fix theme={"system"}
      if user.active? do
        refresh_session(user)
      else
        deactivate_session(user)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Keep with clauses focused on matching">
    Move ordinary assignments before `with` and side-effect calls into its body.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      with ref = make_ref(),
           {:ok, user} <- Accounts.create_user(ref),
           Logger.info("created #{user.id}") do
        user
      end
      ```

      ```elixir Fix theme={"system"}
      ref = make_ref()

      with {:ok, user} <- Accounts.create_user(ref) do
        Logger.info("created #{user.id}")
        user
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not store runtime configuration in module attributes">
    Module attributes are evaluated at compile time and can freeze environment-specific configuration.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      @pool_size Application.get_env(:my_app, :pool_size)
      def pool_size, do: @pool_size
      ```

      ```elixir Fix theme={"system"}
      def pool_size do
        Application.fetch_env!(:my_app, :pool_size)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid boolean operations on the same value">
    Repeating the same boolean operand is redundant and may hide a typo.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      ready? and ready?
      ```

      ```elixir Fix theme={"system"}
      ready?
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove dbg calls">
    `dbg/2` is intended for local debugging and should not remain in committed application code.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      user = Accounts.fetch_user!(id) |> dbg()
      ```

      ```elixir Fix theme={"system"}
      user = Accounts.fetch_user!(id)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid expensive empty-enumerable checks">
    Use `Enum.empty?/1` instead of traversing an enumerable to count every element.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Enum.count(users) == 0
      ```

      ```elixir Fix theme={"system"}
      Enum.empty?(users)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove IEx.pry calls">
    `IEx.pry` pauses a running process and must not remain in application code.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def handle_request(conn) do
        IEx.pry()
        process(conn)
      end
      ```

      ```elixir Fix theme={"system"}
      def handle_request(conn) do
        process(conn)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Remove IO.inspect calls">
    Replace temporary console inspection with intentional structured logging when diagnostics are needed.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      user
      |> IO.inspect(label: "loaded user")
      |> authorize()
      ```

      ```elixir Fix theme={"system"}
      Logger.debug("loaded user", user_id: user.id)
      authorize(user)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Configure Logger metadata keys">
    Metadata passed to Logger should be included in the formatter configuration so it is not silently omitted.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      # config: metadata: [:request_id]
      Logger.error("payment failed", error_code: :card_declined)
      ```

      ```elixir Fix theme={"system"}
      # config: metadata: [:request_id, :error_code]
      Logger.error("payment failed", error_code: :card_declined)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid operations on the same value">
    Using the same expression on both sides often produces a trivial result or signals a copy-paste error.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      remaining = total - total
      ```

      ```elixir Fix theme={"system"}
      remaining = total - paid
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid operations with constant results">
    Replace expressions whose result cannot change with the value they represent.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      discounted_total = total * 0
      ```

      ```elixir Fix theme={"system"}
      discounted_total = 0
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Preserve stack traces when raising inside rescue">
    Use `reraise/2` when translating an exception so the original stack trace is retained.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      rescue
        error -> raise MyApp.LoadError, message: Exception.message(error)
      ```

      ```elixir Fix theme={"system"}
      rescue
        error ->
          wrapped = MyApp.LoadError.exception(message: Exception.message(error))
          reraise wrapped, __STACKTRACE__
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Reference struct types correctly in specs">
    Referencing `Module.t()` avoids an unnecessary compile-time dependency on a struct literal.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      @spec send_email(%MyApp.User{}) :: :ok
      ```

      ```elixir Fix theme={"system"}
      @spec send_email(MyApp.User.t()) :: :ok
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid unsafe command execution">
    Do not send a constructed command string through a shell. Pass a fixed executable and separate arguments.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      :os.cmd(~c"convert #{input_path} output.png")
      ```

      ```elixir Fix theme={"system"}
      System.cmd("convert", [input_path, "output.png"])
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Enum operation results">
    `Enum` functions return new values; they do not mutate the input collection.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Enum.sort(users)
      render(users)
      ```

      ```elixir Fix theme={"system"}
      sorted_users = Enum.sort(users)
      render(sorted_users)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use File operation results">
    Handle the success or error returned by `File` operations.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      File.write(path, contents)
      :ok
      ```

      ```elixir Fix theme={"system"}
      case File.write(path, contents) do
        :ok -> :ok
        {:error, reason} -> {:error, reason}
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Keyword operation results">
    `Keyword` functions return updated lists and do not mutate the original.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Keyword.put(options, :timeout, 5_000)
      request(options)
      ```

      ```elixir Fix theme={"system"}
      options = Keyword.put(options, :timeout, 5_000)
      request(options)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use List operation results">
    `List` functions return updated lists and do not mutate the original.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      List.delete(users, deleted_user)
      notify(users)
      ```

      ```elixir Fix theme={"system"}
      users = List.delete(users, deleted_user)
      notify(users)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Path operation results">
    Use the path returned by `Path` functions.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Path.expand(path)
      File.read(path)
      ```

      ```elixir Fix theme={"system"}
      expanded_path = Path.expand(path)
      File.read(expanded_path)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Regex operation results">
    Use the value returned by `Regex` operations.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Regex.replace(~r/\s+/, value, " ")
      save(value)
      ```

      ```elixir Fix theme={"system"}
      normalized = Regex.replace(~r/\s+/, value, " ")
      save(normalized)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use String operation results">
    Strings are immutable, so transformation results must be used.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      String.trim(name)
      create_user(name)
      ```

      ```elixir Fix theme={"system"}
      name = String.trim(name)
      create_user(name)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use Tuple operation results">
    Tuple operations return a new tuple and do not mutate the original.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      Tuple.append(point, z)
      draw(point)
      ```

      ```elixir Fix theme={"system"}
      point = Tuple.append(point, z)
      draw(point)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use the correct test file extension">
    ExUnit test files should use `.exs` so they are executed as scripts by the test runner.

    <CodeGroup>
      ```text Bad theme={"system"}
      test/my_app/user_test.ex
      ```

      ```text Fix theme={"system"}
      test/my_app/user_test.exs
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not evaluate untrusted Elixir code">
    Values derived from a request must not reach `Code.eval_*`, which executes code with the application's privileges.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def evaluate(conn) do
        Code.eval_string(conn.params["expression"])
      end
      ```

      ```elixir Fix theme={"system"}
      def evaluate(conn) do
        expression = conn.params["expression"]
        SafeExpressionParser.evaluate(expression)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not dynamically apply untrusted functions">
    Untrusted values must not choose the module or function passed to `apply/3`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def dispatch(params) do
        apply(String.to_existing_atom(params["module"]), params["function"], [])
      end
      ```

      ```elixir Fix theme={"system"}
      def dispatch(%{"action" => "refresh"}), do: Sessions.refresh()
      def dispatch(%{"action" => "logout"}), do: Sessions.logout()
      def dispatch(_params), do: {:error, :unsupported_action}
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not evaluate untrusted EEx templates">
    EEx templates can execute Elixir code, so only application-owned template source should be evaluated.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def preview(conn) do
        EEx.eval_string(conn.params["template"], assigns: conn.assigns)
      end
      ```

      ```elixir Fix theme={"system"}
      def preview(conn) do
        Phoenix.Template.render(MyAppWeb, "preview", "html", conn.assigns)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not load untrusted native libraries">
    An attacker-controlled path passed to `:erlang.load_nif` can execute arbitrary native code.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def load_native(conn) do
        :erlang.load_nif(conn.params["library"], 0)
      end
      ```

      ```elixir Fix theme={"system"}
      @library Path.join(:code.priv_dir(:my_app), "native/my_app_nif")
      def load_native, do: :erlang.load_nif(@library, 0)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid command injection through :os.cmd">
    `:os.cmd` invokes a command processor and must not receive constructed or untrusted commands.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def lookup(conn) do
        :os.cmd(~c"nslookup #{conn.params["host"]}")
      end
      ```

      ```elixir Fix theme={"system"}
      def lookup(conn) do
        host = validate_hostname!(conn.params["host"])
        System.cmd("nslookup", [host])
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid command injection through Port.open">
    Do not let untrusted input select a command or shell string passed to `Port.open`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def run(conn) do
        Port.open({:spawn, conn.params["command"]}, [:binary])
      end
      ```

      ```elixir Fix theme={"system"}
      def run(argument) do
        executable = System.find_executable("convert")
        Port.open({:spawn_executable, executable}, [{:args, [argument]}, :binary])
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Validate System.cmd commands and arguments">
    Use a fixed executable and validate every argument before passing it to `System.cmd`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def convert(conn) do
        System.cmd(conn.params["program"], conn.params["arguments"])
      end
      ```

      ```elixir Fix theme={"system"}
      def convert(conn) do
        input = validate_image_path!(conn.params["input"])
        System.cmd("convert", [input, "output.png"])
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid command injection through System.shell">
    `System.shell` invokes a system shell and must not receive untrusted input.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def archive(conn) do
        System.shell("tar -czf archive.tgz #{conn.params["path"]}")
      end
      ```

      ```elixir Fix theme={"system"}
      def archive(conn) do
        path = validate_archive_path!(conn.params["path"])
        System.cmd("tar", ["-czf", "archive.tgz", path])
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Validate Phoenix WebSocket origins">
    Disabling socket origin checks allows malicious sites to open authenticated cross-origin WebSocket connections.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      socket "/socket", MyAppWeb.UserSocket,
        websocket: [check_origin: false]
      ```

      ```elixir Fix theme={"system"}
      socket "/socket", MyAppWeb.UserSocket,
        websocket: [check_origin: ["https://app.example.com"]]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid wildcard CORS origins">
    A wildcard CORS policy can allow arbitrary websites to read authenticated responses.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      plug CORSPlug, origin: "*"
      ```

      ```elixir Fix theme={"system"}
      plug CORSPlug, origin: ["https://app.example.com"]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not reuse state-changing actions for GET routes">
    A controller action that changes state must not also be reachable by GET, which is not protected as a state-changing request.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      get "/account/delete", AccountController, :delete
      delete "/account", AccountController, :delete
      ```

      ```elixir Fix theme={"system"}
      get "/account", AccountController, :show
      delete "/account", AccountController, :delete
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Disable Phoenix debug errors outside development">
    Detailed error pages can disclose stack traces, source code, and request data.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      config :my_app, MyAppWeb.Endpoint,
        debug_errors: true
      ```

      ```elixir Fix theme={"system"}
      config :my_app, MyAppWeb.Endpoint,
        debug_errors: false
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Enable Phoenix force_ssl in production">
    Production endpoints should redirect HTTP to HTTPS and enable transport protections.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      config :my_app, MyAppWeb.Endpoint,
        force_ssl: false
      ```

      ```elixir Fix theme={"system"}
      config :my_app, MyAppWeb.Endpoint,
        force_ssl: [rewrite_on: [:x_forwarded_proto]]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Secure session cookies">
    Session cookies should use `secure`, `http_only`, and an appropriate SameSite policy.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      plug Plug.Session,
        store: :cookie,
        key: "_my_app_key",
        secure: false,
        http_only: false
      ```

      ```elixir Fix theme={"system"}
      plug Plug.Session,
        store: :cookie,
        key: "_my_app_key",
        secure: true,
        http_only: true,
        same_site: "Lax"
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Configure a Content Security Policy">
    Secure browser headers should include a restrictive Content Security Policy to reduce the impact of XSS.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      plug :put_secure_browser_headers, %{}
      ```

      ```elixir Fix theme={"system"}
      plug :put_secure_browser_headers, %{
        "content-security-policy" => "default-src 'self'; object-src 'none'"
      }
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Enable CSRF protection in browser pipelines">
    Every browser pipeline that fetches a cookie-backed session and accepts state changes should use `:protect_from_forgery`.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      pipeline :browser do
        plug :accepts, ["html"]
        plug :fetch_session
      end
      ```

      ```elixir Fix theme={"system"}
      pipeline :browser do
        plug :accepts, ["html"]
        plug :fetch_session
        plug :protect_from_forgery
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Enable secure browser headers">
    HTML pipelines should install Phoenix's standard security headers.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      pipeline :browser do
        plug :accepts, ["html"]
        plug :fetch_session
      end
      ```

      ```elixir Fix theme={"system"}
      pipeline :browser do
        plug :accepts, ["html"]
        plug :fetch_session
        plug :put_secure_browser_headers
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use cryptographically secure randomness">
    Pseudo-random generators such as `:rand` must not create tokens, credentials, or other security-sensitive values.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      reset_token = :rand.uniform(1_000_000) |> Integer.to_string()
      ```

      ```elixir Fix theme={"system"}
      reset_token =
        :crypto.strong_rand_bytes(32)
        |> Base.url_encode64(padding: false)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid weak cryptographic hashes">
    MD5 and SHA-1 are collision-prone. Use SHA-256 or stronger for integrity and a password-hashing function for passwords.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      digest = :crypto.hash(:sha, payload)
      ```

      ```elixir Fix theme={"system"}
      digest = :crypto.hash(:sha256, payload)
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Avoid atom-table exhaustion">
    Atoms are not garbage collected, so untrusted strings must not be converted into new atoms.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      role = String.to_atom(conn.params["role"])
      ```

      ```elixir Fix theme={"system"}
      def parse_role("admin"), do: {:ok, :admin}
      def parse_role("member"), do: {:ok, :member}
      def parse_role(_role), do: {:error, :invalid_role}
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not compile untrusted regular expressions">
    Attacker-controlled patterns can trigger excessive backtracking and consume scheduler time.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def search(conn, value) do
        Regex.run(Regex.compile!(conn.params["pattern"]), value)
      end
      ```

      ```elixir Fix theme={"system"}
      @allowed_patterns %{"email" => ~r/^[^\s]+@[^\s]+$/}
      def search(conn, value) do
        Regex.run(Map.fetch!(@allowed_patterns, conn.params["pattern"]), value)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not deserialize untrusted Erlang terms">
    `:erlang.binary_to_term` can allocate attacker-controlled terms and deserialize executable functions.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def decode(conn) do
        :erlang.binary_to_term(conn.body_params["data"])
      end
      ```

      ```elixir Fix theme={"system"}
      def decode(conn) do
        Jason.decode(conn.body_params["data"])
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prevent open redirects">
    Do not let a request parameter select an arbitrary external redirect destination.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def continue(conn, %{"next" => next}) do
        redirect(conn, external: next)
      end
      ```

      ```elixir Fix theme={"system"}
      def continue(conn, %{"next" => "dashboard"}) do
        redirect(conn, to: ~p"/dashboard")
      end

      def continue(conn, _params), do: redirect(conn, to: ~p"/")
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prevent filesystem path traversal">
    Do not pass request-controlled paths directly to filesystem APIs.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def read(conn) do
        File.read(conn.params["path"])
      end
      ```

      ```elixir Fix theme={"system"}
      @documents %{"guide" => "guide.pdf", "terms" => "terms.pdf"}
      def read(conn) do
        filename = Map.fetch!(@documents, conn.params["document"])
        File.read(Path.join(:code.priv_dir(:my_app), "documents/#{filename}"))
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prevent path traversal in send_download">
    Resolve a trusted identifier to a server-owned file instead of accepting a download path from the request.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def download(conn, %{"path" => path}) do
        send_download(conn, {:file, path})
      end
      ```

      ```elixir Fix theme={"system"}
      def download(conn, %{"report" => report_id}) do
        report = Reports.fetch_authorized!(conn.assigns.current_user, report_id)
        send_download(conn, {:file, report.stored_path})
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prevent path traversal in send_file">
    Only send files resolved beneath an application-owned directory.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def asset(conn) do
        Plug.Conn.send_file(conn, 200, conn.params["path"])
      end
      ```

      ```elixir Fix theme={"system"}
      @assets %{"logo" => "logo.svg"}
      def asset(conn) do
        filename = Map.fetch!(@assets, conn.params["asset"])
        path = Path.join(:code.priv_dir(:my_app), "static/#{filename}")
        Plug.Conn.send_file(conn, 200, path)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Use parameterized Ecto SQL queries">
    Never interpolate request values into raw SQL. Keep SQL text fixed and pass values as parameters.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def find_user(conn) do
        Ecto.Adapters.SQL.query!(Repo, "SELECT * FROM users WHERE id = #{conn.params["id"]}")
      end
      ```

      ```elixir Fix theme={"system"}
      def find_user(conn) do
        Ecto.Adapters.SQL.query!(
          Repo,
          "SELECT * FROM users WHERE id = $1",
          [conn.params["id"]]
        )
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Prevent server-side request forgery">
    Do not let untrusted input control an outbound request URL. Resolve destinations from an allowlist.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def fetch(conn) do
        Req.get!(conn.params["url"])
      end
      ```

      ```elixir Fix theme={"system"}
      @services %{"billing" => "https://billing.example.com/health"}
      def fetch(conn) do
        Req.get!(Map.fetch!(@services, conn.params["service"]))
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Verify TLS certificates">
    Disabling certificate verification allows a network attacker to impersonate the remote service.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      :httpc.request(:get, {url, []}, [ssl: [verify: :verify_none]], [])
      ```

      ```elixir Fix theme={"system"}
      :httpc.request(
        :get,
        {url, []},
        [ssl: [verify: :verify_peer, cacerts: :public_key.cacerts_get()]],
        []
      )
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not let users select response content types">
    An attacker who selects `text/html` may turn otherwise inert response data into executable script.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def show(conn) do
        conn
        |> put_resp_content_type(conn.params["content_type"])
        |> send_resp(200, conn.params["body"])
      end
      ```

      ```elixir Fix theme={"system"}
      def show(conn) do
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(200, Jason.encode!(%{message: conn.params["body"]}))
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Escape dynamic Phoenix HTML responses">
    Do not concatenate untrusted data into an HTML response. Render it through Phoenix's escaping.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def welcome(conn, %{"name" => name}) do
        html(conn, "<h1>Welcome #{name}</h1>")
      end
      ```

      ```elixir Fix theme={"system"}
      def welcome(conn, %{"name" => name}) do
        render(conn, :welcome, name: name)
      end
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not pass untrusted HTML to raw">
    `raw` bypasses Phoenix HTML escaping and can turn request data into executable markup.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      raw(@conn.params["message"])
      ```

      ```elixir Fix theme={"system"}
      @conn.params["message"]
      ```
    </CodeGroup>
  </Accordion>

  <Accordion title="Do not send untrusted HTML with send_resp">
    Use a template or an encoder with an explicit non-HTML content type instead of constructing response bodies from request data.

    <CodeGroup>
      ```elixir Bad theme={"system"}
      def echo(conn) do
        send_resp(conn, 200, "<p>#{conn.params["message"]}</p>")
      end
      ```

      ```elixir Fix theme={"system"}
      def echo(conn) do
        body = Jason.encode!(%{message: conn.params["message"]})

        conn
        |> put_resp_content_type("application/json")
        |> send_resp(200, body)
      end
      ```
    </CodeGroup>
  </Accordion>
</AccordionGroup>
