こんにちは、かつコーチです。
PostgreSQLを触り始めると、赤い文字のERROR:メッセージに何度も出くわします。
最初は焦りますが、実は出てくるエラーの種類はある程度パターン化されています。
この記事では、初中級者がつまずきやすいPostgreSQLのエラーを実際のエラーメッセージ付きでまとめ、それぞれの原因と対処法を解説します。
「このエラー文でググってここに辿り着いた」という使い方もできるよう、エラーメッセージをそのまま載せています。
接続まわりのエラー
role “xxx” does not exist
psqlでログインしようとしたときに、最もよく見るエラーの1つです。
$ psql -U taro -d myapp
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: role "taro" does not exist
これは、指定したロール(ユーザー)がPostgreSQLサーバーに存在しないために起こります。
インストール直後はpostgresロールしか存在しないため、独自のロールを使いたい場合は事前に作成しておく必要があります。
-- postgresロールで接続してから、必要なロールを作成する
CREATE ROLE taro WITH LOGIN PASSWORD 'change_this_password';
FATAL: password authentication failed for user
パスワードは合っているはずなのに、認証エラーになるケースです。
$ psql -U app_user -d myapp
psql: error: FATAL: password authentication failed for user "app_user"
原因の多くは、pg_hba.conf(接続方式ごとの認証設定ファイル)の設定です。
# pg_hba.conf の設定例
# TYPE DATABASE USER ADDRESS METHOD
host all all 127.0.0.1/32 scram-sha-256
METHOD列がtrust(無条件許可)になっていると、逆にパスワードなしで通ってしまうため意図がずれます。
scram-sha-256(PostgreSQL 16での推奨方式)になっているか、パスワードの打ち間違いがないかを順に確認します。
設定変更後は、必ずpg_ctl reloadもしくはサーバーの再起動を忘れないようにしてください。
制約・型に関するエラー
duplicate key value violates unique constraint
一意制約(UNIQUE制約)に違反したときに出るエラーです。
INSERT INTO users (email, name) VALUES ('taro@example.com', '田中太郎');
ERROR: duplicate key value violates unique constraint "users_email_key"
DETAIL: Key (email)=(taro@example.com) already exists.
DETAIL行に、実際に重複した値まで表示されるのがPostgreSQLの親切なところです。
このエラーが出たら、まずDETAILを確認し、本当に重複を防ぎたいのか、あるいは既存行を更新したいのかを判断します。
「既存なら更新、なければ挿入」をしたい場合は、UPSERT(別記事で解説したON CONFLICT句)を使うとエラーを出さずに処理できます。
-- ❌ エラーになる可能性がある通常のINSERT
INSERT INTO users (email, name) VALUES ('taro@example.com', '田中太郎');
-- ✅ 重複時は更新するON CONFLICTを使う
INSERT INTO users (email, name) VALUES ('taro@example.com', '田中太郎')
ON CONFLICT (email) DO UPDATE SET name = EXCLUDED.name;
invalid input syntax for type integer
型が合わないデータを挿入・比較しようとしたときのエラーです。
SELECT * FROM orders WHERE id = 'abc';
ERROR: invalid input syntax for type integer: "abc"
LINE 1: SELECT * FROM orders WHERE id = 'abc';
^
idカラムがinteger型なのに、文字列'abc'を渡してしまったために発生します。
アプリケーションのコードで、URLパラメータなどの文字列をそのままSQLに渡してしまうケースでよく起こります。
アプリ側で数値変換のバリデーション(PHPならis_numeric()、ctype_digit()など)を通してからクエリに渡すようにすると防げます。
null value in column violates not-null constraint
NOT NULL制約が付いたカラムに、値を指定せずにINSERTしようとしたときのエラーです。
INSERT INTO products (name, price) VALUES ('ノートPC', NULL);
ERROR: null value in column "price" of relation "products" violates not-null constraint
DETAIL: Failing row contains (1, ノートPC, null, ...).
DETAIL行に、実際に挿入しようとしていた行全体が表示されるため、どのカラムが欠けていたかを特定しやすくなっています。
フォームのバリデーション漏れが原因であることが多いため、アプリ側の必須項目チェックを見直すのが根本対応です。
権限・スキーマに関するエラー
permission denied for table
権限不足で操作が拒否されたときのエラーです。
DELETE FROM orders WHERE id = 100;
ERROR: permission denied for table orders
前回・前々回の記事(ロール権限管理、Row-Level Security)で扱った通り、PostgreSQLは操作ごとに細かく権限を制御できます。
このエラーが出たら、まず現在のロールに必要な権限が付与されているかを確認します。
-- 自分のロールが持つ orders テーブルへの権限を確認
SELECT privilege_type
FROM information_schema.role_table_grants
WHERE table_name = 'orders' AND grantee = current_user;
権限が足りない場合は、管理者ロールでGRANTを実行してもらう必要があります。
relation “xxx” does not exist
テーブル名のタイプミスや、想定と違うスキーマを見ているときに出るエラーです。
SELECT * FROM order;
ERROR: relation "order" does not exist
LINE 1: SELECT * FROM order;
^
HINT: Perhaps you meant to reference the table "orders".
PostgreSQLは似た名前のテーブルがあるとHINTで候補を提示してくれることがあり、これは単純なタイポで気づける親切な機能です。
複数のスキーマを使っている場合は、search_path(スキーマの検索順序)の設定によって「存在するはずのテーブルが見えない」ということも起こります。
-- 現在のsearch_pathを確認する
SHOW search_path;
意図したスキーマが含まれているか確認し、必要であればSET search_path TO ...で調整します。
エラー調査を効率化するコツ
エラーコードで検索する
PostgreSQLのエラーには、23505(一意制約違反)のようなSQLSTATEコードが割り当てられています。
-- アプリケーションのログにエラーコードが出ている場合、公式ドキュメントの
-- 「Appendix A. PostgreSQL Error Codes」で意味を調べられる
-- 例: 23505 = unique_violation
アプリケーションのフレームワーク(Laravel、Djangoなど)によっては、生のエラーメッセージではなくSQLSTATEコードだけがログに残ることもあるため、コードと原因の対応を覚えておくと調査が速くなります。
ログレベルを上げて詳細を確認する
エラーメッセージだけでは原因が分からない場合、postgresql.confのlog_statementをallにして、実行されたSQL文自体をログに残す方法も有効です。
# postgresql.conf(調査時のみ一時的に設定、常時ONは非推奨)
log_statement = 'all'
本番環境で常時有効にするとログ量が膨大になるため、障害調査時だけ一時的に有効化し、調査が終わったら元に戻すことを忘れないようにしてください。
まとめ
この記事のポイント
- 接続エラーの多くは、ロールの存在確認と
pg_hba.confの認証方式チェックで解決する - 制約違反のエラーは
DETAIL行に具体的な値が出るため、必ず確認してから対処する - 権限エラーはロール権限管理・RLSの設定を見直すきっかけとして活用する
- SQLSTATEコードとログレベルの調整を覚えておくと、原因調査のスピードが上がる
次に読むべき記事
- ロールベースの権限管理(CREATE ROLE)
- UPSERT(ON CONFLICT)とRETURNINGで往復を減らす
- PostgreSQLとMongoDB、JSONBはどこまでMongoDBの代わりになるか比較検証
タグ: PostgreSQL, 初心者向け, エラー解決