トラブルシューティング
Multica をセルフホストする際によく遭遇する問題 — 症状、原因、診断方法、解決方法。
症状から問題を探してください。各項目では症状 / 考えられる原因 / 診断方法 / 解決方法を提供します。お使いの状況が一覧にない場合は、GitHub にイシューを登録してください。
デーモンがサーバーに接続できない
症状: multica daemon の status コマンドが offline または connection refused を表示します。サーバーログに /api/daemon/register や /api/daemon/heartbeat のリクエストが見当たりません。デーモンの仕組みについてはデーモンとランタイムを参照してください。
考えられる原因:
MULTICA_SERVER_URLが誤ったアドレスを指している — デフォルト値はws://localhost:8080/wsで、セルフホスト時は自分のサーバーアドレスに変更する必要があります- ネットワーク / ファイアウォールによるブロック — デーモンとサーバーが同じネットワークにいない、またはアウトバウンドトラフィックがブロックされている
- トークンが期限切れまたは無効 —
multica loginを一度も実行していない、または PAT が取り消された - サーバーが登録を拒否した — ログインしたアカウントが対象のワークスペースに所属していない(register が 403 を返す)
- DNS 解決の失敗 — デーモンのマシンでホスト名が解決されない
診断方法:
multica daemon logs --lines 100 # look for daemon-side errors
echo $MULTICA_SERVER_URL # confirm the address is set
curl -i http://<server-host>:8080/health # hit the server directly
curl -i http://<server-host>:8080/readyz # include DB + migration readiness
cat ~/.multica/config.json # verify api_token exists
multica workspace list # confirm you're a member of the target workspace解決方法: 上記の各原因を 1 つずつ対処してください。最もよくある 2 つの解決策は、MULTICA_SERVER_URL を変更してデーモンを再起動すること(multica daemon restart)と、ログインし直すこと(multica logout && multica login)です。
タスクが queued で止まる
症状: エージェントにイシューを割り当てた後、イシューの状態はすぐに in_progress に変わりますが、長時間経ってもページにエージェント実行の兆候が見えません。multica daemon status はデーモンを online と表示しています。
考えられる原因(頻度順):
- エージェントの同時実行上限に到達 — このエージェントの
max_concurrent_tasks(デフォルト 6)が、他の実行中タスクですでに埋まっている - 同じイシューで同じエージェントの別タスクがまだ実行中 — 同じエージェント × 同じイシューは順次実行が強制されます(重複実行の防止)
- エージェントがアーカイブされている — アーカイブ後も新しいタスクはキューに入りますが、クレームできず、5 分後にタイムアウトします(code-issue G-01)
- デーモンが現在のワークスペースにこのランタイムを登録していない — デーモンを再起動するか、UI でランタイムを選択し直してください
- デーモンの接続が切れた — 直近 45 秒間ハートビートがありません。
daemon statusがonlineと表示されるのは、ごく最近切断された状態を反映している可能性があります
診断方法:
multica daemon status --output json # runtime list + last_seen_at
multica agent list # check agent archived state
multica issue show <issue-id> # inspect task historyサーバー側(セルフホスト)では、"no_tasks" / "no_capacity" を grep してクレームの結果を確認できます。
解決方法:
- 同時実行が満杯 → 実行中のタスクが終わるのを待つか、
multica agent update <id> --max-concurrent-tasks 10で上限を引き上げてください - 同一イシューの順次実行 → 前のタスクが終わるのを待つか、別のエージェントに割り当て直してください
- エージェントがアーカイブされている →
multica agent restore <id> - ランタイム未登録 →
multica daemon restartするとデーモンが再登録します
WebSocket が接続できない
症状: ブラウザのコンソールに WebSocket is closed が記録されます。ページにリアルタイム更新(タスクの進捗、コメント、インボックス)が表示されず、再読み込みしないと見えません。バックエンドのタスクは引き続き実行されます。
考えられる原因:
- Origin チェックの失敗 — フロントエンドのドメインがサーバーの CORS 許可リストにありません。デフォルトの許可リストには
localhost:3000/5173/5174のみが含まれ、公開インターネットでセルフホストするにはFRONTEND_ORIGINが必要です - プロトコルの不一致 —
https://のフロントエンドにはwss://が必要で、HTTP はws://を使います - リバースプロキシが WebSocket アップグレードを有効にしていない — Nginx / Envoy / HAProxy はデフォルトでは
Upgradeヘッダーを転送しません - JWT クッキーの期限切れまたは欠落 — 30 日の有効期限後にログインし直していない
診断方法:
- ブラウザの DevTools → Network → 「WS」でフィルタリングし、接続状態とステータスコードを確認してください
- サーバーログで
"rejected origin"/"websocket"を grep してください — origin の問題であれば明示的に表示されます curl -i http://<server-host>:8080/wsは(Upgradeヘッダー付きで)101 Switching Protocolsを返すはずです
解決方法:
- Origin エラー → サーバーの
.envにFRONTEND_ORIGIN=https://multica.yourdomain.comを設定(またはカンマ区切りのCORS_ALLOWED_ORIGINS)し、サーバーを再起動してください - プロトコルの不一致 →
FRONTEND_ORIGINのプロトコルがフロントエンドと一致しているか確認してください - リバースプロキシ → Nginx に
proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";を追加してください - クッキーの期限切れ → ページを再読み込みしてログインし直してください
メールが届かない
症状: ログインまたは招待の受諾中にメールアドレスを送信したのに、インボックスにもスパムフォルダにも認証コードがありません。
まず、サーバーがどのプロバイダーをアクティブと認識しているかを確認してください。 起動時にバックエンドは次のいずれかを出力します。
EmailService: SMTP relay <host>:<port> from=<addr>— SMTP を使用(SMTP_HOSTが空でなければ Resend より優先)EmailService: Resend API from=<addr>— Resend を使用EmailService: DEV mode — codes printed to stdout …— プロバイダーが構成されていない
docker compose -f docker-compose.selfhost.yml logs backend | grep "EmailService:"期待していた行が見当たらない場合は、環境変数がプロセスに届いていません。.env と docker compose -f docker-compose.selfhost.yml exec backend env | grep -E 'RESEND_|SMTP_' を確認してください。この起動ログの行には認証情報は一切記録されません。
Resend がアクティブなプロバイダーの場合
考えられる原因:
RESEND_API_KEYが設定されていない — サーバーは静かにフォールバックし、エラーを出さずにコードを自身の stdout に書き込みます。プロダクションで陥りやすい落とし穴です- Resend API キーが無効、またはクォータ超過 — サーバーログに
"failed to send verification code"が表示されます RESEND_FROM_EMAILのドメインが Resend で検証されていない — Resend が送信を拒否します- メールは送信されたが受信者の ISP にスパムと判定された — Resend ダッシュボードとスパムフォルダを確認してください
診断方法:
- サーバーログで
"[DEV] Verification code for"を grep してください — これがある場合、Resend が構成されておらず、コードが stdout に書き込まれたことを意味します - Resend ダッシュボード → Emails で送信履歴を確認してください
RESEND_FROM_EMAILのドメインが Resend コンソールの「Verified Domains」リストに表示されるか確認してください
解決方法:
- API キーの欠落 → サインインとサインアップの構成 → メールの仕組みに従って構成し、サーバーを再起動してください
- ドメイン未検証 → Resend コンソールで DNS 検証フローを実行してください(SPF / DKIM レコードを追加)
- 緊急時(内部テスト)→ サーバーログの
[DEV]の下に出力されたコードをコピーしてください
SMTP がアクティブなプロバイダーの場合
SMTP の経路はすべての失敗を失敗した段階とともにラップするため、サーバーログがすでにどの段階で relay がセッションを拒否したかを教えてくれます。"failed to send verification email" / "failed to send invitation email" を grep し、ラップされたエラーを確認してください。
| 記録されたエラー | 意味 | 解決方法 |
|---|---|---|
smtp dial <host>:<port>: dial tcp …: connect: connection refused / i/o timeout | バックエンドコンテナが relay に到達できない — host が誤っている、port が誤っている、ファイアウォール、または relay が待ち受けていない | コンテナ内部から SMTP_HOST / SMTP_PORT が解決されるか確認してください(docker compose -f docker-compose.selfhost.yml exec backend nslookup <host> および nc -vz <host> <port>)。Multica を実行するホストから relay へのファイアウォールを開放してください |
smtp starttls: x509: certificate signed by unknown authority(または certificate is not valid for any names) | relay がプライベート CA / 自己署名証明書を使用しており、コンテナの信頼ストアがそれを拒否している | CA をコンテナにインストールするか、relay が信頼できるネットワークセグメント上で到達可能であることを確認したうえでのみ SMTP_TLS_INSECURE=true を設定してください |
smtp auth: 535 5.7.8 Authentication credentials invalid(または 534/530) | SMTP_USERNAME / SMTP_PASSWORD が誤っている、または relay が PLAIN 以外の認証方式を要求している | メール管理者にサービスアカウントの認証情報を再確認してください。Exchange の匿名内部 relay の場合は両方を空のままにします(SMTP_USERNAME=、SMTP_PASSWORD=) |
smtp MAIL FROM: 550 5.7.1 Client does not have permissions to send as this sender | relay が RESEND_FROM_EMAIL をエンベロープ送信者として受け入れない — 典型的な Exchange の「anonymous users not allowed」または DMARC アラインメントの問題 | RESEND_FROM_EMAIL を relay が受け入れるドメインに設定してください。Exchange では receive connector で送信元 IP に ms-Exch-SMTP-Accept-Any-Sender を付与してください |
smtp RCPT TO <addr>: 550 5.7.1 Unable to relay | relay の receive connector が、あなたのサブネットから外部の受信者への中継を許可していない(外部ドメインと通信する匿名内部 relay で最も多い) | 招待を内部の受信者に制限するか、Multica ホストのサブネットを Exchange の「Anonymous Users → Relay」権限リストに追加してください |
smtp DATA / smtp write body / smtp end data | セッションは受け入れられたが relay が本文を破棄した — 通常はメッセージサイズ制限、コンテンツフィルタリング、または送信途中の接続リセットが原因 | relay のログで同じ Message-ID(ログには <unixnano>@<host> 形式)を確認してください。必要であればメッセージサイズの上限を引き上げてください |
MAIL FROM、RCPT TO、DATA のエラーは常に relay の応答コードとともに記録されるため、反対側の Exchange / Postfix のログと突き合わせることができます。認証コードと招待トークンは、ラップされたエラーに決して含まれません。
診断方法:
- 起動時に
"EmailService: SMTP relay"を一度 grep し、ランタイムの失敗については"failed to send"を grep してください - バックエンドコンテナ内部から接続性を点検してください:
docker compose -f docker-compose.selfhost.yml exec backend sh -c 'nc -vz $SMTP_HOST $SMTP_PORT' - 環境変数がプロセスに届いたか確認してください:
docker compose -f docker-compose.selfhost.yml exec backend env | grep SMTP_(出力にパスワードが含まれるため、信頼できるシェルでのみ実行してください)
解決方法:
- host / port の誤り →
SMTP_HOST/SMTP_PORTを調整してバックエンドを再起動してください。サポートされる relay モードは認証設定 → Option B: SMTP relayを参照してください - 証明書の不一致 → relay の CA をコンテナにインストールするか、信頼できるネットワークセグメントで一時的に
SMTP_TLS_INSECURE=trueを設定してください - 認証の失敗 → 認証情報を再確認してください。匿名内部 relay の場合は
SMTP_USERNAMEとSMTP_PASSWORDを空のままにしてください Unable to relay→ 内部の受信者に制限するか、Exchange の receive connector で Multica ホストの IP に中継権限を付与してください
固定のローカルテストコードが動作しない
症状: セルフホストのインスタンスで 888888 のような固定のローカルテストコードでログインしようとしたところ、invalid or expired code で拒否されます。
考えられる原因(相互に排他的):
MULTICA_DEV_VERIFICATION_CODEが空 — 固定コードはデフォルトで無効ですAPP_ENV=production— これは正しいプロダクション構成です。固定のローカルテストコードはプロダクションでは無視されます- 構成されたコードが 6 桁でない — このショートカットは 6 桁の値のみを受け付けます
診断方法:
cat .env | grep -E 'APP_ENV|MULTICA_DEV_VERIFICATION_CODE'
docker exec <container> env | grep -E 'APP_ENV|MULTICA_DEV_VERIFICATION_CODE'インボックス(スパムを含む)で実際の認証コードを確認してください。
解決方法:
- プロダクションでは
MULTICA_DEV_VERIFICATION_CODEを空のままにし、Resend を構成して実際のコードを使用してください - ローカル開発や内部テストの場合は、サーバーログから生成されたコードをコピーするか、
APP_ENV=developmentとMULTICA_DEV_VERIFICATION_CODE=888888を設定してください — 公開インスタンスでは固定コードを絶対に有効にしないでください(詳細はサインインとサインアップの構成 → 固定のローカルテストコードを参照)
使用量ダッシュボードが 0 のままになる
症状: エージェントはタスクを完了し、生のトークン使用量はデータベースに記録されていますが、設定 → 使用量と設定 → ランタイムで入力 / 出力 / コストがすべて 0 と表示されます。これは静かに発生する現象で、バックエンドログにエラーはありません。
考えられる原因:
rollup_task_usage_hourly()が一切スケジュールされていない — 使用量 / ランタイムのダッシュボードは派生テーブルtask_usage_hourlyから読み取り、このテーブルはその関数によって埋められます。同梱のpgvector/pgvector:pg17イメージにはpg_cronが含まれておらず、バックエンドもプロセス内で rollup を実行しません。外部スケジューラのない新規セルフホストインストールでは、これがデフォルトの状態です。pg_cronはインストールされているが誤ったデータベースを指している —pg_cron.database_nameのデフォルト値はpostgresです。Multica のデータベース名が異なる場合、スケジュールされたジョブはrollup_task_usage_hourly()を一切見つけられません。- スケジューラは動作しているが rollup が静かにエラーを出している — 例えば cron エントリ内部の DB ロール / search_path が誤っている。
診断方法:
-- Confirm raw events exist but the hourly table is empty.
SELECT count(*) AS raw_rows FROM task_usage;
SELECT count(*) AS hourly_rows FROM task_usage_hourly;
-- Confirm pg_cron is (or isn't) available.
SELECT * FROM pg_available_extensions WHERE name = 'pg_cron';
SHOW shared_preload_libraries;
-- If pg_cron is installed, check the schedule + last run.
SELECT jobname, schedule, database, active FROM cron.job;
SELECT jobname, status, return_message, start_time, end_time
FROM cron.job_run_details ORDER BY start_time DESC LIMIT 10;
-- Watermark — if this is 1970-01-01, the rollup has never run.
SELECT watermark_at FROM task_usage_hourly_rollup_state;解決方法:
- rollup を手動で一度呼び出して動作するか確認してください:
SELECT rollup_task_usage_hourly();— ダッシュボードを再読み込みしてください。数値が表示されれば、欠けているのはスケジューラだけです。 - セルフホストクイックスタート → 使用量 rollup のスケジューリングからサポートされる方式のいずれかを選んでください: 外部 cron / systemd-timer / Kubernetes CronJob、または Postgres を
pg_cronを含むイメージに置き換える。 - スケジュール設定より前の履歴がすでにある場合は、バックエンドコンテナ内部で
backfill_task_usage_hourlyを実行し、ウォーターマーク以前のバケットを埋めてください。
マイグレーション 103 が refusing to drop legacy daily rollups で失敗する
症状: v0.3.4 から v0.3.5+ にアップグレードする際、バックエンドコンテナが起動しない(または migrate up が中断する)とともに、次のエラーが発生します。
ERROR: refusing to drop legacy daily rollups:
task_usage_hourly_rollup_state.watermark_at (1970-01-01 ...) trails
task_usage latest event (...) by more than 01:00:00 — backfill is
incomplete or pg_cron is not running. Run cmd/backfill_task_usage_hourly
(and let pg_cron catch up) before re-running migrate考えられる原因: これはマイグレーション 103 の fail-closed ガードです。task_usage_hourly が生の task_usage に追いつくまで、レガシーの daily rollup の削除を拒否します。既存の行が存在し、rollup のウォーターマークがまだ epoch に留まっているとき — つまり、まだどの履歴も hourly テーブルに rollup されていないとき — にこのガードが発動します。
解決方法:
-
同じデータベースに対して backfill を実行してください(冪等であり、中断しても安全で、再実行しても安全です):
# Docker Compose docker compose -f docker-compose.selfhost.yml exec backend \ ./backfill_task_usage_hourly --sleep-between-slices=2s # Kubernetes kubectl -n multica exec deploy/multica-backend -- \ ./backfill_task_usage_hourly --sleep-between-slices=2s -
アップグレードを再実行してください — バックエンドコンテナを再起動するだけで十分で、マイグレーションは起動時に実行されます。これでガードが最新のウォーターマークを確認し、
103の適用を許可します。 -
ウォーターマークが進み続けるように、継続的な rollup スケジュール(cron /
pg_cron)を設定してください — セルフホストクイックスタート → 使用量 rollup のスケジューリングを参照してください。
--sleep-between-slices=2s は、数年分の履歴を持つプロダクションデータベースにとって控えめなデフォルト値です。直近 N か月のみを保持し、それより古いバケットを永久に放棄してもかまわない場合は --months-back N --force-partial を使用してください。
ポートの競合
症状: multica server や multica daemon start が address already in use で失敗します。
考えられる原因:
- サーバーポートが使用中(デフォルト
8080) - デーモンの health ポートが使用中(デフォルト
19514、プロファイルごとにハッシュでオフセット) - Web 開発サーバーのポート競合(
3000/5173) - ポートに対する権限不足(
< 1024の特権ポートのバインドには sudo が必要)
診断方法:
lsof -i :8080 # macOS / Linux
netstat -ano | findstr :8080 # Windows解決方法:
- 競合しているプロセスを終了する(
kill -9 <PID>)か、PORT=9000でポートを変更してください - 80 / 443 を使うには → 直接バインドせず、前段にリバースプロキシ(Nginx / Caddy)を置いて高位ポートへ転送してください
ログの場所
| 構成要素 | 場所 | コマンド |
|---|---|---|
| デーモン | ~/.multica/daemon.log(バックグラウンドモード)またはフォアグラウンドの stdout | multica daemon logs -f --lines 100 |
| サーバー(Docker) | コンテナの stdout | docker logs -f <container> |
| サーバー(systemd) | journal | journalctl -u multica-server -f |
| フロントエンド(dev) | pnpm dev を実行中のターミナル | 直接確認 |
| フロントエンド(ブラウザ) | DevTools → Console | F12 を押す |
より詳細なデーモンログが必要な場合は、デーモンをバックグラウンドからフォアグラウンドに移してください: multica daemon stop && multica daemon start --foreground。