MeWrite Docs

Elixir: FunctionClauseError

Elixirでパターンマッチする関数節がない場合のエラー

概要

Elixirで関数を呼び出した際に、引数にマッチする関数節(clause)が見つからない場合に発生するエラーです。

エラーメッセージ

** (FunctionClauseError) no function clause matching in MyModule.my_function/1
    (my_app) lib/my_module.ex:5: MyModule.my_function(:unexpected)

原因

  1. パターンの網羅性不足: すべての入力パターンをカバーしていない
  2. 型の不一致: 期待する型と異なる引数が渡された
  3. ガード条件の不備: ガード条件がfalseになるケースがある
  4. nil の未処理: nilが渡されることを想定していない

解決策

1. デフォルト節を追加

1
2
3
4
5
6
7
8
9
# 悪い例
def greet(:morning), do: "おはよう"
def greet(:evening), do: "こんばんは"
# greet(:afternoon) で FunctionClauseError

# 良い例
def greet(:morning), do: "おはよう"
def greet(:evening), do: "こんばんは"
def greet(_), do: "こんにちは"  # デフォルト節

2. ガード条件を緩和

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 悪い例
def process(n) when is_integer(n) and n > 0 do
  n * 2
end
# process(-1) や process("5") でエラー

# 良い例
def process(n) when is_integer(n) and n > 0, do: n * 2
def process(n) when is_integer(n), do: 0
def process(_), do: {:error, :invalid_input}

3. nil を明示的に処理

1
2
3
4
5
6
7
8
# 悪い例
def get_name(%{name: name}), do: name
# get_name(nil) でエラー

# 良い例
def get_name(nil), do: "Unknown"
def get_name(%{name: name}), do: name
def get_name(_), do: "Unknown"

4. with 構文で安全に処理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def process_user(params) do
  with {:ok, name} <- Map.fetch(params, :name),
       {:ok, age} <- Map.fetch(params, :age),
       true <- is_integer(age) do
    {:ok, %{name: name, age: age}}
  else
    :error -> {:error, :missing_field}
    false -> {:error, :invalid_age}
  end
end

5. case 式で明示的にマッチ

1
2
3
4
5
6
7
8
def handle_result(result) do
  case result do
    {:ok, value} -> value
    {:error, reason} -> raise "Error: #{reason}"
    nil -> nil
    other -> raise "Unexpected: #{inspect(other)}"
  end
end

6. Dialyzer で型チェック

1
2
3
4
# @spec で期待する型を明示
@spec divide(number(), number()) :: {:ok, float()} | {:error, :division_by_zero}
def divide(_, 0), do: {:error, :division_by_zero}
def divide(a, b), do: {:ok, a / b}

7. 入力検証を追加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def create_user(params) when is_map(params) do
  with {:ok, name} <- validate_name(params[:name]),
       {:ok, email} <- validate_email(params[:email]) do
    {:ok, %User{name: name, email: email}}
  end
end

def create_user(_), do: {:error, :invalid_params}

defp validate_name(name) when is_binary(name) and byte_size(name) > 0 do
  {:ok, name}
end
defp validate_name(_), do: {:error, :invalid_name}

8. 関数節の順序に注意

1
2
3
4
5
6
7
# 悪い例:デフォルト節が先
def process(_), do: :default  # これが常にマッチ
def process(:special), do: :special  # 到達しない

# 良い例:具体的なパターンを先に
def process(:special), do: :special
def process(_), do: :default

よくある間違い

  • リストの先頭・残りパターン [head | tail] で空リストを考慮していない
  • マップのキーが存在しない場合を考慮していない
  • バイナリパターンマッチでサイズが足りない
  • 再帰の終了条件がない

Elixir の他のエラー

最終更新: 2025-12-09