---
title: トラブルシューティング
description: Multica をセルフホストする際によく遭遇する問題 — 症状、原因、診断方法、解決方法。
---

import { Callout } from "fumadocs-ui/components/callout";

症状から問題を探してください。各項目では**症状 / 考えられる原因 / 診断方法 / 解決方法**を提供します。お使いの状況が一覧にない場合は、[GitHub](https://github.com/multica-ai/multica/issues) にイシューを登録してください。

## デーモンがサーバーに接続できない

**症状**: [`multica daemon`](/cli) の `status` コマンドが `offline` または `connection refused` を表示します。サーバーログに `/api/daemon/register` や `/api/daemon/heartbeat` のリクエストが見当たりません。デーモンの仕組みについては[デーモンとランタイム](/daemon-runtimes)を参照してください。

**考えられる原因**:

1. **`MULTICA_SERVER_URL` が誤ったアドレスを指している** — デフォルト値は `ws://localhost:8080/ws` で、セルフホスト時は自分のサーバーアドレスに変更する必要があります
2. **ネットワーク / ファイアウォールによるブロック** — デーモンとサーバーが同じネットワークにいない、またはアウトバウンドトラフィックがブロックされている
3. **トークンが期限切れまたは無効** — `multica login` を一度も実行していない、または PAT が取り消された
4. **サーバーが登録を拒否した** — ログインしたアカウントが対象のワークスペースに所属していない（register が 403 を返す）
5. **DNS 解決の失敗** — デーモンのマシンでホスト名が解決されない

**診断方法**:

```bash
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` と表示しています。

**考えられる原因**（頻度順）:

1. **エージェントの同時実行上限に到達** — このエージェントの `max_concurrent_tasks`（デフォルト 6）が、他の実行中タスクですでに埋まっている
2. **同じイシューで同じエージェントの別タスクがまだ実行中** — 同じエージェント × 同じイシューは順次実行が強制されます（重複実行の防止）
3. **エージェントがアーカイブされている** — アーカイブ後も新しいタスクはキューに入りますが、クレームできず、5 分後にタイムアウトします（code-issue G-01）
4. **デーモンが現在のワークスペースにこのランタイムを登録していない** — デーモンを再起動するか、UI でランタイムを選択し直してください
5. **デーモンの接続が切れた** — 直近 45 秒間ハートビートがありません。`daemon status` が `online` と表示されるのは、ごく最近切断された状態を反映している可能性があります

**診断方法**:

```bash
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` が記録されます。ページにリアルタイム更新（タスクの進捗、コメント、インボックス）が表示されず、再読み込みしないと見えません。バックエンドのタスクは引き続き実行されます。

**考えられる原因**:

1. **Origin チェックの失敗** — フロントエンドのドメインがサーバーの CORS 許可リストにありません。デフォルトの許可リストには `localhost:3000/5173/5174` のみが含まれ、公開インターネットでセルフホストするには `FRONTEND_ORIGIN` が必要です
2. **プロトコルの不一致** — `https://` のフロントエンドには `wss://` が必要で、HTTP は `ws://` を使います
3. **リバースプロキシが WebSocket アップグレードを有効にしていない** — Nginx / Envoy / HAProxy はデフォルトでは `Upgrade` ヘッダーを転送しません
4. **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 …` — プロバイダーが構成されていない

```bash
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 がアクティブなプロバイダーの場合

**考えられる原因**:

1. **`RESEND_API_KEY` が設定されていない** — サーバーは静かにフォールバックし、エラーを出さずに**コードを自身の stdout に書き込みます**。プロダクションで陥りやすい落とし穴です
2. **Resend API キーが無効、またはクォータ超過** — サーバーログに `"failed to send verification code"` が表示されます
3. **`RESEND_FROM_EMAIL` のドメインが Resend で検証されていない** — Resend が送信を拒否します
4. **メールは送信されたが受信者の ISP にスパムと判定された** — Resend ダッシュボードとスパムフォルダを確認してください

**診断方法**:

- サーバーログで `"[DEV] Verification code for"` を grep してください — これがある場合、Resend が構成されておらず、コードが stdout に書き込まれたことを意味します
- [Resend ダッシュボード](https://resend.com/) → Emails で送信履歴を確認してください
- `RESEND_FROM_EMAIL` のドメインが Resend コンソールの「Verified Domains」リストに表示されるか確認してください

**解決方法**:

- API キーの欠落 → [サインインとサインアップの構成 → メールの仕組み](/auth-setup#how-email--verification-code-sign-in-works)に従って構成し、サーバーを再起動してください
- ドメイン未検証 → 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](/auth-setup)を参照してください
- 証明書の不一致 → relay の CA をコンテナにインストールするか、信頼できるネットワークセグメントで一時的に `SMTP_TLS_INSECURE=true` を設定してください
- 認証の失敗 → 認証情報を再確認してください。匿名内部 relay の場合は `SMTP_USERNAME` と `SMTP_PASSWORD` を空のままにしてください
- `Unable to relay` → 内部の受信者に制限するか、Exchange の receive connector で Multica ホストの IP に中継権限を付与してください

## 固定のローカルテストコードが動作しない

**症状**: セルフホストのインスタンスで `888888` のような固定のローカルテストコードでログインしようとしたところ、`invalid or expired code` で拒否されます。

**考えられる原因**（相互に排他的）:

1. **`MULTICA_DEV_VERIFICATION_CODE` が空** — 固定コードはデフォルトで無効です
2. **`APP_ENV=production`** — これは**正しい**プロダクション構成です。固定のローカルテストコードはプロダクションでは無視されます
3. **構成されたコードが 6 桁でない** — このショートカットは 6 桁の値のみを受け付けます

**診断方法**:

```bash
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` を設定してください — 公開インスタンスでは固定コードを絶対に有効にしないでください（詳細は[サインインとサインアップの構成 → 固定のローカルテストコード](/auth-setup#fixed-local-testing-codes)を参照）

## 使用量ダッシュボードが 0 のままになる

**症状**: エージェントはタスクを完了し、生のトークン使用量はデータベースに記録されていますが、**設定 → 使用量**と**設定 → ランタイム**で入力 / 出力 / コストがすべて 0 と表示されます。これは静かに発生する現象で、バックエンドログにエラーはありません。

**考えられる原因**:

1. **`rollup_task_usage_hourly()` がクレームされていない** — 使用量 / ランタイムのダッシュボードは派生テーブル `task_usage_hourly` から読み取り、このテーブルはその関数によって埋められます。MUL-2957 以降、バックエンドは DB バックドのスケジューラー（`sys_cron_executions`）を介してこの rollup をインプロセスで実行します。古いビルド、未適用の migration `113`、またはレプリカが残っていない長時間のバックエンド停止があると、最近の SUCCESS 行のないテーブルが残ることがあります。
2. **`pg_cron` は互換性のために構成されているが誤ったデータベースを指している** — `pg_cron.database_name` のデフォルトは `postgres` です。Multica データベース名が異なる場合、スケジュールされたジョブは `rollup_task_usage_hourly()` を一切見つけられません。インプロセススケジューラーはこれに依存しませんが、もしインプロセススケジューラーを除去して `pg_cron` に依存している場合、DB 名は一致しなければなりません。
3. **ハンドラーがクレームされているが静かにエラーを出している** — マイグレーションが部分的にしか適用されていないために SQL 関数が欠落している、あるいは DB ロール / search_path が誤って構成されている、など。`sys_cron_executions` の FAILED 監査行を確認してください。

**診断方法**:

```sql
-- 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;

-- Inspect the in-process scheduler's audit log.
SELECT plan_time, status, attempt, runner_id,
       error_code, error_msg, started_at, finished_at
  FROM sys_cron_executions
 WHERE job_name = 'rollup_task_usage_hourly'
 ORDER BY plan_time DESC
 LIMIT 20;

-- Watermark — if this is 1970-01-01, the rollup has never run.
SELECT watermark_at FROM task_usage_hourly_rollup_state;

-- Compatibility path: if you previously registered pg_cron, confirm
-- it is (or isn't) available and pointing at the right database.
SELECT * FROM pg_available_extensions WHERE name = 'pg_cron';
SHOW shared_preload_libraries;
SELECT jobname, schedule, database, active FROM cron.job;
```

**解決方法**:

- 少なくとも 1 つのバックエンドレプリカでスケジューラーが実際に動作していることを確認してください — 30 秒ごとに `sys_cron_executions` の `rollup_task_usage_hourly` に SUCCESS 行が追加されているはずです。
- SQL パスを検証するため、rollup を手動で一度呼び出してください: `SELECT rollup_task_usage_hourly();` — ダッシュボードを再読み込みしてください。数値が表示されれば SQL 関数は問題なく、スケジューラーのクレーム経路に問題があります。
- migration `113_sys_cron_executions` がまだ適用されていない場合は、バックエンドを再起動してマイグレーションを実行するか、手動で `migrate up` を呼び出してください。
- インプロセススケジューラー以前のレガシー `pg_cron` 履歴がある場合でも、SQL 関数は内部で advisory lock 4246 を保持するため二重書き込みは発生しません — オプションの `cron.unschedule` クリーンアップについては [セルフホストクイックスタート → 使用量ロールアップ](/self-host-quickstart#7-usage-rollup-no-operator-action-required) を参照してください。

## マイグレーション `103` が `refusing to drop legacy daily rollups` で失敗する

**症状**: `v0.3.4` から `v0.3.5+` にアップグレードする際、バックエンドコンテナが起動しない（または `migrate up` が中断する）とともに、次のエラーが発生します。

```text
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 されていないとき — にこのガードが発動します。

MUL-2957 以降、migrate コマンドは migration `103` を適用する直前に冪等な月別スライス backfill（advisory lock 4246 の下）を自動で実行するため、v0.3.4 → v0.3.5+ への直接アップグレードは単一の `migrate up` 呼び出しで完了します。それでもこのエラーが表示される場合は、MUL-2957 以前のバイナリを使用しているか、フック自体が失敗しています — 直前の `task_usage hourly rollup hook` 行で migrate ログを確認してください。

**解決方法**:

1. MUL-2957 以前のバイナリを使用しており、まずバイナリをアップグレードできない場合は、同じデータベースに対してスタンドアロンの backfill を実行してください（冪等であり、中断しても安全で、再実行しても安全です）:

   ```bash
   # 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
   ```

2. アップグレードを再実行してください — バックエンドコンテナを再起動するだけで十分で、マイグレーションは起動時に実行されます。これでガードが最新のウォーターマークを確認し、`103` の適用を許可します。
3. インプロセススケジューラーがウォーターマークを進め続けます — [セルフホストクイックスタート → 使用量ロールアップ](/self-host-quickstart#7-usage-rollup-no-operator-action-required) を参照してください。

`--sleep-between-slices=2s` は、数年分の履歴を持つプロダクションデータベースにとって控えめなデフォルト値です。直近 N か月のみを保持し、それより古いバケットを永久に放棄してもかまわない場合は `--months-back N --force-partial` を使用してください。

## ポートの競合

**症状**: `multica server` や `multica daemon start` が `address already in use` で失敗します。

**考えられる原因**:

1. **サーバーポートが使用中**（デフォルト `8080`）
2. **デーモンの health ポートが使用中**（デフォルト `19514`、プロファイルごとにハッシュでオフセット）
3. **Web 開発サーバーのポート競合**（`3000` / `5173`）
4. **ポートに対する権限不足**（`< 1024` の特権ポートのバインドには sudo が必要）

**診断方法**:

```bash
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`。
