はじめに
結論
今回の私の事象では、コードの書き方や関数使い方が原因ではなく、パスワード認証に失敗しました、のエラーメッセージのUTF-8でのデコードに失敗したための UnicodeDecodeError
のようです。
PostgreSQLの動いているサーバーがWindowsServerで、ロケールがShift_JISになっているのかなと予想しています(まだ未確認です)。
同じような事象が発生した方は、IDやパスワードなどが間違っていないか、ご自身の設定を一度確認してみてください。
動作環境
- Python: 3.12.0
- psycopg: 2.9.10
- PostgreSQL: 15
* 記事の標準出力はスクロールを減らすために適当なタイミングで手動で改行をはさんでいます
* IPアドレスは適当なものに置き換えているのでUnicodeDecodeErrorのstart, endは合っていないかもしれません
問題が発生したコードとエラー
当該部分のコードの抜粋版が以下のようなものになります。
import psycopg2
host = "192.168.100.100"
port = 5432
database = "postgres"
username = "postgres"
password = "hogehoge"
conn = psycopg2.connect(
host=host,
port=port,
dbname=database,
user=username,
password=password,
connect_timeout=3,
)
...
実行と、発生したエラーメッセージは以下の通りです。
Traceback (most recent call last):
File "C:\***********\main.py", line 17, in <module>
conn = psycopg2.connect(
^^^^^^^^^^^^^^^^^
File "C::\***********\env\Lib\site-packages\psycopg2\__init__.py", line 122, in connect
conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 65: invalid start byte
UnicodeDecodeErrorの内容を深堀りしてみる
エラーの型とメッセージの確認
Tracebackに書かれている通りではあるのですが、例外処理のブロックを作成してprint文で型とメッセージを出力するように変更します
try:
conn = psycopg2.connect(...)
except Exception as e:
print(type(e))
print(e)
<class 'UnicodeDecodeError'>
'utf-8' codec can't decode byte 0x83 in position 65: invalid start byte
reprを使用した評価する
ここでExceptionを repr
を使用して評価します。repr関数はオブジェクトの内容を人間が読めるような形に変換して文字列として返してくれる関数です。
except Exception as e:
print(repr(e))
UnicodeDecodeError('utf-8', b'connection to server at"192.168.100.100",
port 5432 failed: FATAL: \x83\x86\x81[\x83U\x81["postgres"
\x82\xcc\x83p\x83X\x83\x8f\x81[\x83h\x94F\x8f\xd8\x82\xc9\x8e
\xb8\x94s\x82\xb5\x82\xdc\x82\xb5\x82\xbd\n', 65, 66, 'invalid start byte')
メッセージ部分をデコードする
reprの結果から x83\x86\...
を utf-8
でデコードしようとしているのが分かるので、メッセージ部分を shift_jis
でデコードし、出力するようなコードにしてみます。
except Exception as e:
print(e.args[1].decode("shift_jis"))
connection to server at "192.168.100.100", port 5432
failed: FATAL: ユーザー"postgres"のパスワード認証に失敗しました
ということで今回の渡しの場合は、設定ファイルのミスでパスワード認証に失敗していることが原因のエラーでした。
パスワード以外の設定不備によるエラーメッセージの検証
ついでに、パスワード以外の設定不備によるエラーメッセージを確認していきます。
結果一覧、×はUnicodeDecodeError
設定不備の項目 | 結果 |
---|---|
ホスト名 | ○ |
ポート番号 | ○ |
データベース名 | × |
ユーザー名 | × |
パスワード | × |
try:
conn = psycopg2.connect(
host=host,
port=port,
dbname=database,
user=username,
password=password,
connect_timeout=3,
)
except Exception as e:
print(repr(e))
# 適宜コメントイン・コメントアウト
# print(e.args[1].decode("shift_jis"))
存在しないホストを指定した場合
エラーの型はOperationalErrorでメッセージもちゃんと出力されそう。
OperationalError('connection to server at "192.168.1.1",
port 5432 failed: timeout expired\n')
ポート番号が不正
上記と同じ
データベース名が間違っている場合
UnicodeDecodeErrorになる。エラー内容はデータベース○○○○は存在しません。
UnicodeDecodeError('utf-8', b'connection to server at "192.168.100.100",
port 5432 failed: FATAL: \x83f\x81[\x83^\x83x\x81[\x83X"hogehoge"\x82
\xcd\x91\xb6\x8d\xdd\x82\xb5\x82\xdc\x82\xb9\x82\xf1\n', 65, 66, 'invalid start byte')
---
connection to server at "192.168.100.100", port 5432 failed: FATAL:
データベース"hogehoge"は存在しません
存在しないユーザーを指定した場合
パスワードが間違っている場合と同じ。
UnicodeDecodeError('utf-8', b'connection to server at "192.168.100.100",
port 5432 failed: FATAL: \x83\x86\x81[\x83U\x81["hogeeeeee"\x82
\xcc\x83p\x83X\x83\x8f\x81[\x83h\x94F\x8f\xd8\x82\xc9\x8e\xb8\x94s\x82\xb5\x82\xdc\x82\xb5\x82\xbd\n', 65, 66, 'invalid start byte')
---
connection to server at "192.168.100.100", port 5432 failed: FATAL:
ユーザー"hogeeeeee"のパスワード認証に失敗しました