> ## Documentation Index
> Fetch the complete documentation index at: https://docs.befailproof.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Fehlerbehebung

> AgentEye-Dokumentation zur Fehlerbehebung.

Dieser Leitfaden ordnet die häufigsten Symptome in der Produktionsumgebung einer konkreten Diagnose und Lösung zu, damit Sie Vorfälle mit vorhandenen Werkzeugen beheben können – ohne zusätzliche Observability-Infrastruktur aufbauen zu müssen. Er behandelt Server, Collector, Dashboard, KI-Assistent, Python SDK, Gesundheits- und Zertifikatsüberwachung, Backups, ClickHouse-basierte Analytics und Multi-Tenancy.

Dashboard-Seiten sind unter `/<org-slug>/…` org-scoped, und der Ereignisstrom ist die Org-Startseite (`/<org-slug>/`). Seitennamen in diesem Leitfaden (z. B. `/sessions`, `/queries`) beziehen sich auf diese org-scoped Routen.

***

## Logs anzeigen

AgentEye bündelt keinen Logging- oder Monitoring-Stack. Sowohl der Server als auch das Dashboard schreiben strukturierte Logs nach **stdout**, sodass Sie diese direkt mit `kubectl` oder `docker` lesen können – kein Aggregator erforderlich.

### Kubernetes

Live-Logs für Server und Dashboard verfolgen:

```bash theme={null}
kubectl logs -n agenteye -l app=server    -f --timestamps
kubectl logs -n agenteye -l app=dashboard -f --timestamps
```

Nützliche Varianten:

| Ziel                                 | Befehl                                                            |
| ------------------------------------ | ----------------------------------------------------------------- |
| Letzte 200 Zeilen (kein Follow)      | `kubectl logs -n agenteye -l app=server --tail=200 --timestamps`  |
| Logs des vorherigen Absturzes        | `kubectl logs -n agenteye <pod-name> --previous`                  |
| Alle Replikas gleichzeitig verfolgen | `kubectl logs -n agenteye -l app=server --max-log-requests=10 -f` |
| Postgres (StatefulSet)               | `kubectl logs -n agenteye postgres-0 -f`                          |

### Docker Compose

```bash theme={null}
docker logs -f agenteye-server
docker logs -f agenteye-dashboard
```

### Eine einzelne Anfrage über Dashboard und Server korrelieren

Jede Dashboard-Anfrage erhält eine `request_id`, die über den `x-request-id`-Header an den Server weitergeleitet wird. Der Server gibt sie in seinen Antwort-Headern und in jeder Log-Zeile für diese Anfrage wieder aus. Um eine Anfrage von Anfang bis Ende zu verfolgen:

1. ID aus dem Antwort-Header erfassen, z. B.:
   ```bash theme={null}
   curl -i https://dashboard.example.com/api/events | grep -i x-request-id
   # x-request-id: 9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   ```
2. Logs beider Pods nach dieser ID durchsuchen:
   ```bash theme={null}
   REQ=9a7b0d6e-5e9b-4c0a-9f8a-5f1e4b5c0f3a
   kubectl logs -n agenteye -l app=dashboard --tail=5000 | grep "$REQ"
   kubectl logs -n agenteye -l app=server    --tail=5000 | grep "$REQ"
   ```

Sie sehen die `proxy passthrough`-, `withAuth: authorized`- und `upstream response`-Zeilen des Dashboards zusammen mit dem `http request received` / `http request completed`-Paar des Servers – alle mit derselben `request_id`.

### JSON-Logs und `jq`

Setzen Sie `AE_LOG_JSON=1` am Dashboard (standardmäßig aktiviert, wenn `NODE_ENV=production`), um ein JSON-Objekt pro Zeile auszugeben. Dann strukturell filtern:

```bash theme={null}
kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.level == "warn" or .level == "error")'

kubectl logs -n agenteye -l app=dashboard --tail=5000 \
  | jq 'select(.route == "POST /api/keys")'
```

Der Rust-Server gibt `key=value`-Tracing-Paare aus, die sich gut mit `grep` ohne `jq` durchsuchen lassen:

```bash theme={null}
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'status=5'   # 5xx
kubectl logs -n agenteye -l app=server --tail=5000 | grep 'actor_key_id='
```

### Ausführlichkeit erhöhen

| Komponente | Env-Variable   | Beispiel                                                    |
| ---------- | -------------- | ----------------------------------------------------------- |
| Server     | `RUST_LOG`     | `RUST_LOG=debug` oder `RUST_LOG=agenteye_server=debug,info` |
| Dashboard  | `AE_LOG_LEVEL` | `AE_LOG_LEVEL=debug`                                        |

`debug` am Server fügt eine `api key authenticated`-Zeile pro Authentifizierung hinzu. `debug` am Dashboard fügt `upstream request`-, `session validated`- und `proxy passthrough`-Zeilen hinzu.

### Log-Aufbewahrung

Container-stdout ist flüchtig; kubelet rotiert Log-Dateien (Standard ca. 10 MiB pro Container) und hält eine kleine Anzahl auf der Festplatte. Sobald ein Pod gelöscht wird, sind die Logs verschwunden. Wenn Sie eine längere Aufbewahrung oder pod-übergreifende Suche benötigen, richten Sie Ihren Cluster auf einen Log-Collector (Loki, CloudWatch, Cloud Logging, Datadog usw.) ein, der `/var/log/containers/` verfolgt. AgentEye schreibt keine bestimmte Lösung vor.

***

## Authentifizierungsprobleme

### `docker pull` schlägt fehl mit "unauthorized"

Stellen Sie sicher, dass Sie Docker mit Ihrem `AGENTEYE_TOKEN` gegen GHCR authentifiziert haben:

```bash theme={null}
echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin
```

Das Token muss die Berechtigung `read:packages` für die `agenteye-enterprise`-Organisation haben. Kontaktieren Sie `support@exosphere.host`, wenn Ihr Token nicht funktioniert.

### `gh release download` gibt 404 oder 401 zurück

* Bestätigen Sie, dass `AGENTEYE_TOKEN` in Ihrer Shell exportiert ist: `echo $AGENTEYE_TOKEN`
* Bestätigen Sie, dass Sie `GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download ...` verwenden (die `gh`-CLI liest `GITHUB_TOKEN`)
* Das Token benötigt `contents:read` auf `agenteye-enterprise/releases`

***

## Server-Probleme

### Server schlägt fehl mit "invalid port number"

Das `POSTGRES_PASSWORD` (oder eine andere Anmeldeinformation) enthält URL-Sonderzeichen (`/`, `+`, `=`), die das Parsen der `DATABASE_URL` stören. Generieren Sie das Passwort mit Hex-Kodierung neu:

```bash theme={null}
NEW_PASS=$(openssl rand -hex 24)
```

Aktualisieren Sie dann das Kubernetes-Secret und das Passwort in Postgres (oder erstellen Sie die `.env` für Docker Compose neu) und starten Sie den Server neu. Siehe die vollständigen Schritte in [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment) § "PostgreSQL credentials".

### Server beendet sich sofort beim Start

Überprüfen Sie die Container-Logs:

```bash theme={null}
docker logs agenteye-server
```

Häufige Ursachen:

* `DATABASE_URL` nicht gesetzt oder fehlerhaft: Der Server protokolliert den Fehler und beendet sich.
* Postgres ist nicht erreichbar: Bestätigen Sie, dass der Postgres-Container oder die verwaltete DB läuft und Host/Port korrekt sind.
* Migrationen fehlgeschlagen: Prüfen Sie die Logs auf SQL-Fehler.

### `GET /health` gibt non-200 zurück oder läuft ab

Der Server führt beim ersten Start möglicherweise noch Migrationen durch. Warten Sie einige Sekunden und versuchen Sie es erneut:

```bash theme={null}
curl http://localhost:8080/health
```

Wenn das Problem anhält, prüfen Sie `docker logs agenteye-server` auf Fehler.

### `GET /ready` gibt 503 zurück

`/ready` ist der Readiness-Probe: Er gibt `503` zurück, wenn der Server **Postgres oder ClickHouse** nicht erreichen kann. Der Body benennt die fehlschlagende Abhängigkeit:

```bash theme={null}
curl -s http://localhost:8080/ready
# {"status":"not_ready","checks":{"postgres":"ok","clickhouse":"down","redis":"ok"}}
```

Beheben Sie die als `down` gemeldete Abhängigkeit: Ist der ClickHouse-/Postgres-Pod `Running`? Ist `CLICKHOUSE_URL` / `DATABASE_URL` korrekt und erreichbar? In Kubernetes liest der Pod `NotReady`, bis `/ready` sich erholt; das ist erwartet und genau das Signal, auf das die Gesundheitsüberwachung alarmiert. Redis ist niemals eine Ursache: Es wird gemeldet, verursacht aber keinen Readiness-Fehler.

### Collector gibt 401 Unauthorized zurück

Der API-Schlüssel des Collectors hat keine `events:add`-Berechtigung, oder der Schlüssel wurde deaktiviert. Erstellen Sie einen neuen Schlüssel mit der richtigen Berechtigung:

```bash theme={null}
curl -s -X POST http://your-server:8080/keys \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"new-collector","permissions":["events:add"]}'
```

### Authentifizierte Anfragen sind plötzlich langsam (\~200ms statt \~5ms)

Dies ist das Symptom, wenn Redis ausgefallen ist, während `REDIS_URL` gesetzt ist. Jeder Cache-Aufruf läuft nach 100ms ab und fällt dann auf Postgres zurück; auf Auth- und OTP-Pfaden macht die Anfrage zwei solche Fallbacks.

Bestätigen in den Server-Logs:

```
auth cache: L2 get failed error=redis call timed out
```

Lösung:

1. `redis-cli -h <your-redis> ping` um zu bestätigen, dass Redis im Cluster-Netzwerk erreichbar ist.
2. Wenn Redis kurz ausgefallen war und jetzt wieder läuft, **starten Sie die Server-Pods neu**. Der `redis::aio::ConnectionManager` stellt die Verbindung nach einem Verbindungsabbruch nicht zuverlässig wieder her; ein Pod-Neustart nimmt die neue Verbindung sauber auf. Dasselbe gilt für das Dashboard.
3. Wenn Sie Redis derzeit nicht betreiben möchten, entfernen Sie `REDIS_URL` aus dem Deployment und starten Sie neu. Beide Dienste laufen ohne Cache (Korrektheit bleibt erhalten; Latenz kehrt zum Pre-Redis-Ausgangswert zurück).

### Server meldet `OTP request rate-limited` in den Logs, aber der Benutzer sagt, er hat es nur einmal versucht

Prüfen Sie, ob Redis unerreichbar war. Der Fallback-Pfad verwendet `SELECT COUNT(*) FROM otp_codes WHERE created_at > now() - interval '15 minutes'`, der zuvor generierte OTP-Zeilen sieht. Wenn der Benutzer eine Stunde lang auf "Erneut senden" geklickt hat, kann das 15-Minuten-Fenster noch ≥5 Codes enthalten. Lösung: entweder warten, bis das Fenster abläuft, oder `DELETE FROM otp_codes WHERE user_id = $1 AND created_at > now() - interval '15 minutes'` (Operator-Konsole).

### Ich habe `ALLOWED_EMAILS` / `SESSION_TTL_SECS` / `OTP_TTL_SECS` geändert und neu gestartet; nichts hat sich geändert

Diese Env-Variablen sind **nur beim ersten Start als Seeds** gedacht. Sobald die `settings`-Tabelle eine Zeile für den entsprechenden Schlüssel hat, ist diese Zeile die Quelle der Wahrheit; die Env-Variable wird nur beim ersten Start gelesen und bei jedem nachfolgenden Neustart ignoriert.

Um sie nach dem ersten Start zu ändern, melden Sie sich am Dashboard an und bearbeiten Sie sie unter `/settings`. Die Änderung gilt innerhalb von Sekunden für alle Replikas; kein Neustart erforderlich.

Wenn Sie einen erneuten Seed aus der Env erzwingen müssen (selten, typischerweise nur in der Entwicklung nützlich), führen Sie `DELETE FROM settings WHERE key = '<key>'` aus und starten Sie den Server neu. Der Bootstrap nimmt den aktuellen Env-Variablenwert beim nächsten Start auf. Das Bearbeiten über `/settings` ist der unterstützte Weg in der Produktion.

***

## Collector-Probleme

### Collector startet, aber Ereignisse erscheinen nicht im Dashboard

1. Bestätigen Sie, dass der Collector läuft: `systemctl status agenteye-collector` (Linux) oder prüfen Sie den Prozess.
2. Bestätigen Sie, dass `AGENTEYE_URL` auf `http(s)://your-server-host:8080/events` zeigt (Hinweis: `/events`-Pfad).
3. Führen Sie einen einmaligen Flush aus, um sofortige Ausgabe zu sehen:
   ```bash theme={null}
   agenteye-collector flush
   ```
4. Prüfen Sie, ob das Python SDK tatsächlich Dateien schreibt: `ls ${AGENTEYE_HOME:-~/.agenteye}/events/`
5. Wenn Dateien in `${AGENTEYE_HOME:-~/.agenteye}/failed/` vorhanden sind, schlagen die Uploads fehl. Prüfen Sie die Collector-Logs auf den Fehler – wahrscheinlich ein 4xx (falscher Schlüssel oder URL) oder ein Netzwerkproblem.

### Dateien häufen sich in `$AGENTEYE_HOME/events/` an und werden nicht hochgeladen

* Der Collector läuft möglicherweise nicht. Starten Sie ihn: `agenteye-collector start`; er leert beim Start automatisch vorhandene Ereignisse.
* Collector-Zustand prüfen: `agenteye-collector health`
* Der Collector läuft möglicherweise, kann aber den Server nicht erreichen. Prüfen Sie die Firewall-Regeln zwischen Collector- und Server-Hosts.

### Dateien in `$AGENTEYE_HOME/failed/`

Dateien werden nach Erschöpfung aller Wiederholungsversuche (Standard: 5 Versuche mit exponentiellem Backoff) nach `failed/` verschoben. Das bedeutet entweder:

* Der Server hat einen 4xx-Fehler zurückgegeben (falscher Schlüssel, falsche URL oder Payload-Problem)
* Der Server war während des gesamten Wiederholungsfensters nicht erreichbar

Beheben Sie das zugrunde liegende Problem und stellen Sie dann manuell erneut in die Warteschlange:

```bash theme={null}
mv ${AGENTEYE_HOME:-~/.agenteye}/failed/*.jsonl ${AGENTEYE_HOME:-~/.agenteye}/events/
agenteye-collector flush
```

### Collector meldet bei jedem Upload `network error` (TLS-Handshake schlägt fehl)

Wenn `curl -k` gegen `AGENTEYE_URL` erfolgreich ist, aber das Collector-Binary jeden Upload mit `error sending request for url (...)` fehlschlagen lässt, präsentiert der AgentEye-Server ein TLS-Zertifikat, das nicht von einer öffentlich vertrauenswürdigen CA signiert ist.

Der **Produktionspfad** ist der ACME-Ingest-Hostname, der in `deploy/base/certificates/domain.env` konfiguriert ist (siehe [`kubernetes-deployment.md`](/de/agenteye/kubernetes-deployment) Phase 3.1 / 4.2). Sobald `INGEST_DOMAIN` auf den öffentlichen Traefik-LB auflöst und cert-manager das Let's Encrypt-Zertifikat ausgestellt hat, verifizieren Collectors das Server-Zertifikat gegen den System-Vertrauensspeicher **ohne `AGENTEYE_TLS_CA`**; entfernen Sie es aus Ihrer Collector-Konfiguration, falls es gegen ein älteres selbstsigniertes Deployment gesetzt war.

**Symptom: Collector funktionierte gestern, schlägt heute nach \~90 Tagen fehl.** Das bedeutet, dass das Deployment noch den Legacy-`selfsigned`-Aussteller für `ingest-tls` verwendet. Das 90-Tage-Zertifikat wurde rotiert und die gepinnte CA-Datei ist veraltet. Dauerhaft beheben, indem Sie den Cluster auf den ACME-Aussteller umstellen (Phase 3.1 des Deployment-Leitfadens). Kurzfristige Lösung: das aktuelle Server-Zertifikat neu extrahieren und `AGENTEYE_TLS_CA` aktualisieren:

```bash theme={null}
kubectl get secret ingest-tls-cert -n agenteye \
  -o jsonpath='{.data.tls\.crt}' | base64 -d > /etc/agenteye/server-ca.crt
```

```bash theme={null}
export AGENTEYE_TLS_CA=/etc/agenteye/server-ca.crt
agenteye-collector flush
```

`AGENTEYE_TLS_CA` fügt einen zusätzlichen Vertrauensanker hinzu; die standardmäßigen öffentlichen Roots werden weiterhin vertraut.

### `ingest-tls`-Zertifikat bleibt nach dem Deploy `Ready: False`

```bash theme={null}
kubectl describe certificate ingest-tls -n agenteye
```

Schauen Sie sich `Events` und den referenzierten `Order` / `Challenge` an. Häufige Ursachen:

* **DNS löst nicht auf den öffentlichen LB auf.** Der HTTP-01-Validator kann `INGEST_DOMAIN` nicht erreichen. Mit `dig +short INGEST_DOMAIN` prüfen; es sollte auf dieselbe Adresse wie die `EXTERNAL-IP` des `traefik-public`-LoadBalancers auflösen. cert-manager wiederholt automatisch, sobald DNS propagiert; das Zertifikat muss nicht gelöscht werden.
* **Port 80 am Load Balancer / Security Group blockiert.** HTTP-01 erfordert, dass Port 80 von Let's Encrypts öffentlichen Validatoren erreichbar ist. Wenn ein vorgeschaltetes WAF oder eine SG `:80` einschränkt, öffnen Sie es (die Traefik-Konfiguration leitet zu HTTPS weiter, aber Boulder folgt der Umleitung und akzeptiert die Antwort).
* **`dnsNames` nicht ersetzt.** Wenn `kubectl get certificate ingest-tls -n agenteye -o jsonpath='{.spec.dnsNames}'` `INGEST_DOMAIN_PLACEHOLDER` anzeigt, haben Sie den `domain.env`-Schritt übersprungen; erstellen Sie es aus `domain.env.example` und wenden Sie es erneut an.
* **Rate-Limit von Let's Encrypt.** Wiederholte fehlgeschlagene Orders für denselben Hostnamen lösen die Limits für doppelte Zertifikate oder fehlgeschlagene Validierungen aus. Warten Sie mindestens eine Stunde vor dem erneuten Versuch; prüfen Sie den Order-Status auf die genaue Rate-Limit-Meldung.

### `dashboard-tls`-Zertifikat bleibt `Ready: False` / Browser zeigt noch eine Warnung

Gleicher Diagnoseablauf wie bei `ingest-tls` oben (`kubectl describe certificate dashboard-tls -n agenteye`); DNS-, Port-80-, Platzhalter- und Rate-Limit-Ursachen gelten alle, plus zwei Dashboard-spezifische:

* **`DASHBOARD_DOMAIN` löst auf den falschen LoadBalancer auf.** Es muss auf den *Dashboard*-Traefik-LB zeigen, nicht auf den öffentlichen Ingest-LB. Mit `dig +short` den Hostnamen prüfen und mit der Dashboard-LB-Adresse vergleichen.
* **Die Dashboard-Traefik-Instanz kann die Challenge nicht bereitstellen.** Sie muss mit der gebündelten Dashboard-Values-Datei installiert sein, die einen bereichsbeschränkten Ingress-Provider für den HTTP-01-Solver von cert-manager aktiviert. Ohne ihn ist der Solver nicht erreichbar und der Order bleibt für immer `pending`. Aktualisieren Sie die Instanz mit den bereitgestellten Values; die ausstehende Challenge wird dann von selbst abgeschlossen.
* **Der LoadBalancer war IP-beschränkt.** Source-Ranges gelten auch für Port 80, was Let's Encrypts Validatoren blockiert – sowohl bei der ersten Ausstellung als auch bei jeder \~75-tägigen Erneuerung. Öffnen Sie den LB erneut oder koordinieren Sie einen DNS-01-Solver mit dem Support, bevor Sie ihn sperren.

Während die Ausstellung fehlschlägt, stellt das Dashboard weiterhin sein vorheriges Zertifikat bereit (oder das Ingress-Standard-Zertifikat bei einer Neuinstallation) – der Zugang ist durch eine Browser-Warnung beeinträchtigt, aber nie unterbrochen.

### CLI überspringt TLS-Verifizierung noch, nachdem das Dashboard ein vertrauenswürdiges Zertifikat erhalten hat

`--insecure` wird bei der Anmeldung in `cli.json` gespeichert. Sobald das Dashboard ein öffentlich vertrauenswürdiges Zertifikat bereitstellt, melden Sie sich erneut mit `agenteye --base-url https://<your-dashboard-domain> --secure login` an; die Verifizierung wird wieder aktiviert gespeichert und die Startup-Warnung verschwindet.

***

## Dashboard-Probleme

### `ADMIN_EMAIL`-Benutzer kann nicht deaktiviert oder bearbeitet werden

Dies ist by Design. Der Benutzer, der `ADMIN_EMAIL` entspricht, wird bei jedem Server-Start als geschützt markiert: Das Dashboard blendet die Deaktivieren-Schaltfläche für diese Zeile aus, und die API lehnt `DELETE /users/:id` und `PUT /users/:id` dagegen mit `403 Forbidden` ab. Ein Datenbank-Trigger lehnt auch direkte `UPDATE`-Anweisungen ab, die die geschützte Zeile deaktivieren würden.

Um den Bootstrap-Admin zu rotieren, ändern Sie `ADMIN_EMAIL` in Ihrer Umgebung und starten Sie den Server neu. Die neue E-Mail wird als geschützt upserted. Der vorherige Admin behält das geschützte Flag, bis es in der Datenbank gelöscht wird (in der Regel in Ordnung, da die vorherige E-Mail ein gültiger Admin bleibt, bis Sie sie explizit entfernen).

### Dashboard zeigt keine Ereignisse

1. Bestätigen Sie, dass die Server-URL und der API-Schlüssel in den Umgebungsvariablen des Dashboards korrekt sind (`AGENTEYE_SERVER_URL`, `AGENTEYE_API_KEY`).
2. Der Dashboard-API-Schlüssel benötigt die Berechtigung `events:read`.
3. Bestätigen Sie, dass tatsächlich Ereignisse aufgenommen wurden: `curl http://your-server:8080/events -H "Authorization: Bearer $ADMIN_KEY"`

### `/errors` ist leer, aber `/events` zeigt rote Zeilen

Neuere SDK-Versionen senden Fehler als `agent_end`- / `tool_result`- / `hook_completed`-Ereignisse mit `outcome: "error"` im Payload statt als dedizierte `event_type: "error"`-Zeile. Die `/errors`-Seite erkennt jetzt beides: Jede Zeile, die der `/events`-Stream rot färbt (explizites `event_type='error'`, Payload `outcome`/`status` in der Fehler-Menge, `is_error: true` oder ein wahrer `error`-Feld), erscheint in `/errors`. Wenn Sie zuvor "keine Fehler in diesem Zeitfenster" sahen, während rote Zeilen in `/events` sichtbar waren, aktualisieren Sie Dashboard und Server zusammen (der erweiterte Filter ist `errored=true` auf `GET /events`) und die beiden Ansichten stimmen überein.

### `/models`, `/tools` oder `/hooks` ist langsam oder schlägt bei breiten Zeitbereichen fehl

**Symptom:** Bei einer großen Ereignistabelle (Millionen von Zeilen) drehen sich beim Öffnen von `/models`, `/tools` oder `/hooks` – oder beim Erweitern des Zeitbereichs auf `7d`, `30d` oder `all` – die Charts und zeigen dann einen Ladefehler. Der Server protokolliert ein ClickHouse-`MEMORY_LIMIT_EXCEEDED` (Code 241) oder einen Query-Timeout für die `latency_aggregate`-Anfrage.

**Ursache:** Ältere Builds berechneten die Latenz- und Verteilungs-Rollups dieser Seiten mit einer Abfrage, die den vollständigen rohen Ereignis-`payload` las und Anfrage-/Antwort-Ereignisse mit einem In-Memory-Sortier-und-Join paarte. Der Query-Spitzenspeicher wuchs daher mit der Fenstergröße, sodass bei einem stark ausgelasteten Tenant ein breiter Bereich die Pro-Query-Speichergrenze von ClickHouse überschreiten konnte.

**Lösung:** Auf einen Build aktualisieren, der diesen Fix enthält. Der Rollup liest jetzt nur die kompakten promoted Columns und paart Ereignisse mit einer Streaming-Aggregation, sodass der Spitzenspeicher nicht mehr mit dem rohen Payload skaliert – breite Fenster bleiben deutlich innerhalb der Speichergrenze und werden in einem Bruchteil der Zeit zurückgegeben. Die Verbesserung ist rein query-seitig: Sie gilt für alle vorhandenen Daten beim nächsten Seitenaufruf, ohne Re-Ingest oder Backfill.

### Dashboard schlägt beim Laden fehl / leere Seite

Prüfen Sie die Dashboard-Container-Logs:

```bash theme={null}
docker logs agenteye-dashboard
```

Die häufigste Ursache ist, dass `AGENTEYE_SERVER_URL` oder `AGENTEYE_API_KEY` fehlt oder auf einen nicht erreichbaren Server zeigt.

### Dashboard-Analytics / Telemetrie

Das Dashboard sendet standardmäßig anonyme Produktnutzungs-Analytics an PostHog, geleitet über den eigenen `/ingest`-Pfad des Dashboards (ein Reverse Proxy zu `https://us.i.posthog.com`). Die First-Party-Weiterleitung verhindert, dass Browser-Werbeblocker sie abfangen. Dies ist unabhängig von der Kernfunktionalität des Dashboards:

* Der **Dashboard-Container** (nicht der Browser) ist derjenige, der PostHog erreicht. Wenn sein ausgehender Zugriff auf `https://us.i.posthog.com` blockiert ist, schlägt die Telemetrie lautlos fehl; das Dashboard funktioniert normal und es werden keine Fehler an Benutzer weitergegeben.
* Es werden niemals Agent-, Sitzungs- oder Ereignisdaten übermittelt, nur Dashboard-UI-Nutzung.
* Um die Telemetrie vollständig zu deaktivieren, setzen Sie `AE_ANALYTICS_DISABLED=1` am Dashboard-Container und starten Sie neu. Siehe [Telemetry & privacy](/de/agenteye/deployment#telemetry--privacy) im Deployment-Leitfaden.

### CLI-Analytics / Telemetrie

Die `agenteye`-CLI sendet standardmäßig anonyme Nutzungs-Analytics an PostHog: welche Befehle ausgeführt werden, Erfolgs-/Exit-Status und Dauer. Dies ist unabhängig von der CLI-Funktionalität:

* Der **Rechner, auf dem die CLI läuft**, erreicht `https://us.i.posthog.com` direkt. Wenn sein ausgehender Zugriff blockiert ist, schlägt die Telemetrie lautlos fehl (das Senden ist zeitlich begrenzt, verzögert also keinen Befehl) und die CLI funktioniert normal.
* Es werden niemals Agent-, Sitzungs- oder Ereignisdaten übermittelt: Befehls-**Argumente und Flag-Werte** (Dashboard-URL, Token, E-Mail, Sitzungs-IDs, Query-Filter) werden niemals gesendet.
* Um es zu deaktivieren, setzen Sie `AGENTEYE_ANALYTICS_DISABLED=1` (oder das tool-übergreifende `DO_NOT_TRACK=1`) in der CLI-Umgebung. Siehe [Telemetry & privacy](/de/agenteye/cli#telemetry--privacy) im CLI-Leitfaden.

***

## KI-Assistent-Probleme

Siehe [enterprise-docs/assistant.md](/de/agenteye/assistant) für die vollständige Einrichtung.

### Die Assistent-Blase erscheint nicht

Die Blase ist ausgeblendet, es sei denn, **alle** folgenden Bedingungen sind erfüllt:

* Der angemeldete Benutzer hat die Berechtigung `agent:use`.
* `AGENTEYE_AGENT_URL` ist am Dashboard gesetzt und der `agent`-Dienst ist erreichbar.
* Ein LLM-Endpunkt ist am `agent`-Dienst konfiguriert (`ANTHROPIC_API_KEY`, ein Gateway über `ANTHROPIC_BASE_URL` oder Bedrock/Vertex). Ohne Konfiguration meldet der Agent "not configured" und die Blase bleibt ausgeblendet.

Prüfen Sie den Zustand des Agents vom Dashboard-Host aus: `curl http://agent:9100/health` sollte `{"status":"ok","llm_configured":true,...}` zurückgeben.

### Der Assistent sagt, er kann etwas nicht lesen

Tools sind pro Benutzer freigegeben. Wenn einem Benutzer `evaluations:read` (oder `events:read`, `dashboards:read`) fehlt, werden die entsprechenden Tools nicht angeboten und der Assistent sagt, er kann diese Daten nicht lesen. Gewähren Sie die entsprechende Leseberechtigung.

### "assistant not configured" (HTTP 503) beim Senden

Der `agent`-Container hat keinen LLM-Endpunkt konfiguriert, oder das `AGENTEYE_AGENT_TOKEN` des Dashboards stimmt nicht mit dem des Agents überein. Setzen Sie beides und starten Sie neu.

### Der `agent`-Container startet neu / OOMs unter Last

Jedes Gespräch spawnt einen kurzlebigen Kindprozess. Stellen Sie sicher, dass der Container mit einem Init-Prozess läuft (das Image verwendet `tini`; in Compose setzen Sie `init: true`) und geben Sie ihm ausreichende Speicherlimits. Reduzieren Sie `AGENTEYE_AGENT_MAX_STEPS` bei Bedarf.

***

## CLI-Probleme

### `agenteye` startet nicht mit `ModuleNotFoundError: No module named 'click'`

Eine frische Installation der `agenteye`-CLI in Version **0.1.6** kann beim Start abstürzen mit:

```
ModuleNotFoundError: No module named 'click'
```

0.1.6 verlässt sich darauf, dass `click` indirekt von `typer` installiert wird; aktuelle `typer`-Releases ziehen es nicht mehr rein, sodass einer sauberen Umgebung das Paket fehlt. **Aktualisieren Sie auf 0.1.7 oder neuer**, was direkt von `click` abhängt:

```bash theme={null}
pipx upgrade agenteye      # wenn mit pipx installiert (oder: pipx install --force agenteye)
uv tool upgrade agenteye   # wenn mit uv installiert
pip install --upgrade agenteye
```

Siehe [enterprise-docs/cli.md](/de/agenteye/cli) für Installationshinweise.

***

## Python SDK-Probleme

### Keine Dateien erscheinen in `$AGENTEYE_HOME/events/`

Das SDK puffert Ereignisse und leert standardmäßig alle 500 ms. Wenn Ihr Prozess vor dem Leeren beendet wird, können Ereignisse verloren gehen. Rufen Sie `agenteye.configure(flush_interval=0.1)` für schnelleres Leeren in kurzlebigen Skripten auf, oder stellen Sie sicher, dass Ihr Prozess lange genug für einen Flush-Zyklus läuft.

Wenn `AGENTEYE_HOME` gesetzt ist, prüfen Sie, ob das SDK nach `$AGENTEYE_HOME/events/` und nicht nach `~/.agenteye/events/` schreibt (erfordert SDK ≥ 0.0.1b5).

### `ValueError: Reserved field names cannot be used as custom fields`

Die Namen `timestamp`, `type` und `environment` sind reserviert und können nicht als benutzerdefinierte Felder verwendet werden. Das Übergeben eines davon löst aus:

```
ValueError: Reserved field names cannot be used as custom fields: [...]
```

Benennen Sie das betreffende benutzerdefinierte Feld um. Beachten Sie, dass `session_id` und `agent_id` explizite Parameter des Ereignisaufrufs sind, keine benutzerdefinierten Felder; das erneute Übergeben eines davon als benutzerdefiniertes Feld löst `TypeError` aus.

***

## Gesundheitsüberwachungs-Probleme

### Keine Alerts in Slack ankommen (Robusta)

Robusta-Gesundheitsalarme sind **opt-in**; es wird nichts gesendet, bis es installiert und auf einen Slack-Kanal ausgerichtet ist. Release und Sink prüfen:

```bash theme={null}
kubectl get pods -n robusta          # robusta-runner + robusta-forwarder sollten Running sein
kubectl logs -n robusta -l app=robusta-runner --tail=50
```

Häufige Ursachen: der Slack-`api_key` / `slack_channel` wurde nicht gesetzt (oder das Token wurde widerrufen); der `api_key` ist ein Robusta Cloud-Relay-Token (`robusta integrations slack`), aber das gebündelte `disableCloudRouting: true` benötigt ein selbst gehostetes Slack-**Bot-Token** (`xoxb-…`), oder setzen Sie `disableCloudRouting: false`; der Sink-`scope` schließt den Namespace aus, in dem Ihre Pods laufen (die gebündelten Values begrenzen auf `agenteye`); oder es ist noch kein Fehler aufgetreten. Erzwingen Sie einen Test-Alert, indem Sie einen Pod herunterfahren:

```bash theme={null}
kubectl -n agenteye delete pod -l app=clickhouse   # wird neu erstellt
```

Siehe [enterprise-docs/health-monitoring.md](/de/agenteye/health-monitoring#2-pod-failure-alerting-with-robusta-opt-in) für Installation und Konfiguration.

### Server flattert dauerhaft `NotReady`

Der Readiness-Probe trifft `/ready`, der fehlschlägt, wenn Postgres oder ClickHouse nicht erreichbar ist. Wenn der Server in und aus `NotReady` wechselt, ist eine Abhängigkeit zeitweise nicht verfügbar; prüfen Sie die ClickHouse- und Postgres-Pods sowie die `CLICKHOUSE_URL` / `DATABASE_URL` des Servers. Prüfen Sie, was `/ready` meldet:

```bash theme={null}
kubectl -n agenteye exec deploy/server -- sh -c 'curl -s localhost:8080/ready'
```

Dieser Probe ist bewusst tolerant (ein großzügiger Fehlerschwellenwert), daher deutet anhaltendes Flattern auf ein echtes Abhängigkeitsproblem hin und nicht auf einen zu aggressiven Probe. Liveness bleibt auf `/health`, daher führt flatternde Readiness **nicht** zum Neustart des Pods.

## Zertifikatsüberwachungs-Probleme

### CronJob sendet keine Slack-Benachrichtigungen

Der `cert-renewal-check`-CronJob benötigt eine Slack-Webhook-URL, die in einem Secret gespeichert ist. Prüfen Sie, ob es vorhanden ist:

```bash theme={null}
kubectl get secret cert-renewal-notify-config -n agenteye
```

Falls fehlend, erstellen Sie es:

```bash theme={null}
kubectl create secret generic cert-renewal-notify-config \
  --namespace agenteye \
  --from-literal=SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
```

Ohne das Secret läuft der CronJob noch und protokolliert Ergebnisse nach stdout. Logs prüfen mit:

```bash theme={null}
kubectl logs -n agenteye -l job-name --tail=50
```

### Client-Zertifikat ist abgelaufen, bevor eine Benachrichtigung empfangen wurde

Der CronJob läuft alle 12 Stunden. Wenn er nicht gelaufen ist, prüfen Sie seinen Status:

```bash theme={null}
kubectl get cronjob cert-renewal-check -n agenteye
```

Eine manuelle Prüfung auslösen:

```bash theme={null}
kubectl create job --from=cronjob/cert-renewal-check manual-cert-check -n agenteye
kubectl logs -n agenteye -l job-name=manual-cert-check
```

Um das abgelaufene Zertifikat sofort neu auszustellen:

```bash theme={null}
cd base/certificates/client-certs
./issue-client-cert.sh <cluster-name>
```

Dann das neu generierte `collector-mtls-secret.yaml` im/in den Cluster(s) anwenden, auf dem/denen Ihre Collectors laufen, und sie neu starten:

```bash theme={null}
kubectl apply -f collector-mtls-secret.yaml -n <collector-namespace>
```

***

## Backup-Probleme

### `agenteye-backup` schlägt fehl mit "No space left on device"

Der `agenteye-backup`-CronJob dumpt Postgres + ClickHouse in ein `backup-tmp`-`emptyDir`-Scratch-Volume (Standard `30Gi`) und **streamt** dann das `tar`-Archiv direkt zu S3 – das komprimierte Archiv wird niemals zurück auf Scratch geschrieben, sodass Scratch nur die *rohen Dumps* halten muss, nicht Dumps plus eine zweite On-Disk-Archivkopie. Ein evictierter Pod / `No space left on device` bedeutet daher, dass die **rohen Dumps** die Scratch-Größe überschreiten (der ClickHouse-`events`-Dump dominiert und wächst im Laufe der Zeit). Prüfen Sie die Logs des fehlgeschlagenen Jobs:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<fehlgeschlagener agenteye-backup-Job>
```

Lösung: Erhöhen Sie in Ihrem Overlay das `backup-tmp`-`emptyDir`-`sizeLimit` des CronJobs über Ihre gesamte rohe Dump-Größe und stellen Sie sicher, dass der Knoten den ephemeren Speicher tatsächlich halten kann (`sizeLimit` ist eine Obergrenze, keine Reservierung). Wenn die Dumps die Festplatte eines einzelnen Knotens überschreiten, ersetzen Sie `emptyDir` durch ein PVC (EBS/PD) für `backup-tmp` oder komprimieren Sie die Dumps an der Quelle.

> Ältere Releases schrieben das `.tar.gz` in denselben `20Gi`-Scratch wie die Dumps, sodass `Dumps + Archiv` ihn überflutete und der Pod **vor** dem Upload evictiert wurde – was wie ein S3-Fehler aussieht, aber eigentlich Festplatte ist. Das Streaming des Uploads beseitigt diese Verdopplung.

### `agenteye-backup` schlägt beim Installieren von `curl` fehl

Der Job läuft auf dem `postgres:16`-Image und installiert `curl` beim Start für den ClickHouse-HTTP-Dump. Auf einem Cluster ohne Egress zu den Debian-Paketspiegeln schlägt der `apt-get`-Schritt fehl. Erlauben Sie entweder diesen Egress vom Backup-Pod oder baken Sie `curl` in ein gespiegeltes/benutzerdefiniertes Backup-Image und referenzieren Sie es in Ihrem Overlay.

### `agenteye-backup` läuft, aber nichts landet im Objektspeicher

Das Base liefert einen echten `BACKUP_BUCKET` (`ts-prod-agenteye/backups`) und das `agenteye-backup`-ServiceAccount. Der Job **streamt** das Archiv zu S3 (`tar cz … | aws s3 cp - s3://…`). Wenn der Backup-Pod keinen Schreibzugriff auf den Bucket hat, gibt der Upload einen Fehler aus – und da das Skript unter `set -euo pipefail` läuft, **schlägt** ein Fehler irgendwo in dieser Pipe den gesamten Job beim `upload`-Schritt fehl statt lautlos nicht zu funktionieren (der EXIT-Trap des Pods protokolliert `backup FAILED during step: upload`). Dies ist auch der Schritt, den Sie *nach* der Behebung einer Scratch-Space-Eviction erreichen, daher prüfen Sie, ob der Upload jetzt landet. Suchen Sie in den Logs des fehlgeschlagenen Jobs nach dem S3-Zugriffsfehler:

```bash theme={null}
kubectl logs -n agenteye -l job-name=<fehlgeschlagener agenteye-backup-Job> | grep -iE 's3|upload|denied'
```

Lösung: Setzen Sie in Ihrem Overlay `BACKUP_BUCKET` auf einen Bucket, den Sie besitzen, und versehen Sie das vorhandene `agenteye-backup`-ServiceAccount mit Schreibzugriff (IRSA / Workload Identity / Pod Identity). Siehe den **Backups**-Abschnitt von [enterprise-docs/kubernetes-deployment.md](/de/agenteye/kubernetes-deployment).

***

## ClickHouse-basierte Evaluierungen / Sitzungen / Abfragen

### Die `/queries`-Seiten-Seitenleiste ist nach dem Upgrade leer

Drei Tabellen (`events`, `evaluations`, `agent_sessions`) werden erwartet. Wenn die SchemaBrowser-Seitenleiste nach dem Upgrade leer ist, hat der Server die ClickHouse-DDL beim Start nicht angewendet. Prüfen Sie die Server-Logs auf `failed to apply CH DDL statement`:

```bash theme={null}
kubectl logs -n agenteye deploy/server | grep -E 'clickhouse|CH DDL'
```

Die häufigste Ursache ist, dass ClickHouse während der Migrationen nicht erreichbar ist. Der Server verweigert den Start, wenn er CH nicht erreichen kann, daher hat ein hängender Pod in der Regel einen `CrashLoopBackOff` statt einer lautlos defekten Abfrageseite, aber eine teilweise DDL-Anwendung (eine Anweisung OK, die nächste 5xx) lässt das Schema halb fertig. Starten Sie den Server-Pod neu, nachdem CH als erreichbar bestätigt wurde:

```bash theme={null}
kubectl rollout restart deploy/server -n agenteye
```

### Neue Evaluierungen erscheinen nicht in `/sessions` oder `/queries`

Nach dem Upgrade werden neue Evaluierungen in ClickHouse geschrieben, nicht in Postgres, und erscheinen unter `/sessions` (durch `evaluations:read` abgesichert) und in `/queries`. Wenn sie nicht erscheinen:

1. Bestätigen Sie, dass die Evaluierungs-Pipeline aktiviert ist (`EVALUATOR_ENDPOINT` am Server gesetzt) und terminale Ergebnisse produziert; prüfen Sie auf `evaluation_finalized`-Log-Zeilen.
2. Bestätigen Sie, dass CH vom Server aus erreichbar ist: `kubectl exec -n agenteye deploy/server -- curl -fsS http://clickhouse:8123/ping`.
3. Die CH-Tabelle stichprobenartig prüfen: `kubectl exec -n agenteye clickhouse-0 -- clickhouse-client -q 'SELECT count() FROM agenteye.evaluations'`.

### Abfragen schlagen unter Last fehl mit "Memory limit exceeded" oder ClickHouse ist `OOMKilled`

**Symptom:** Bei starker Dashboard-/Query-Last schlagen analytische Seiten (Ereignisstrom, `/sessions`, Models-/Latenz-Ansicht, SQL-Editor) fehl oder laufen ab; der Server flattert kurz `NotReady`; und der ClickHouse-Pod zeigt eine steigende Neustart-Anzahl. Dies ist fast immer ein **Speicher**-Problem, kein CPU- oder Festplattenproblem.

**Bestätigen Sie, dass es Speicher ist** (kein Durchsatzproblem, das Replikation lösen würde):

1. Prüfen Sie den Pod auf Out-of-Memory-Kills:
   ```bash theme={null}
   kubectl -n agenteye describe pod clickhouse-0 | grep -iE 'Restart Count|Last State|Reason|OOMKilled'
   ```
   `Reason: OOMKilled` / `Exit Code: 137` mit steigender Neustart-Anzahl ist das Indiz.

2. ClickHouse fragen, was es ablehnt:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT name, value FROM system.errors WHERE value>0 ORDER BY value DESC"
   ```
   Eine große `MEMORY_LIMIT_EXCEEDED`-Anzahl ist die Signatur. Die Meldung lautet *"maximum: N GiB"* – dieses **N ist `0,9 × das Speicherlimit des Pods`** (das `max_server_memory_usage_to_ram_ratio` in `deploy/base/clickhouse/configmap.yaml`). Wenn Ihre schweren Lesevorgänge mehr als N benötigen, werden sie abgelehnt.

3. Schließen Sie aus, was *kein* Problem ist – wenn CPU, Part-Anzahl und Festplatte alle niedrig sind, wäre das Hinzufügen von Replikas/Sharding verschwendete Kosten:
   ```bash theme={null}
   kubectl -n agenteye top pod clickhouse-0
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT table, count() parts FROM system.parts WHERE active AND database='agenteye' GROUP BY table"
   ```

**Ursache:** Das Speicherlimit des ClickHouse-Pods ist zu klein für das analytische Working Set. Die schwersten Lesevorgänge ziehen die rohe JSON-`payload`-Spalte, führen `JSONExtract*` darüber aus und verwenden `FINAL` – jedes kann mehrere GiB benötigen. Wenn die konfigurierten Caches (`mark_cache_size` + `uncompressed_cache_size`) größer als der Pod sind, verschlimmern sie es: Caches werden gegen dasselbe Budget berechnet und verdrängen den Query-Speicher.

**Lösung – ClickHouse-Speicher skalieren:**

1. Erhöhen Sie das ClickHouse-Speicherlimit in Ihrem Overlay, indem Sie die Container-`resources` des `clickhouse`-StatefulSets patchen (derselbe Overlay-Mechanismus wie für die anderen Komponenten). Das nutzbare Server-Budget beträgt `0,9 × Limit`, daher gibt ein `6Gi`-Limit \~5,4 GiB, `16Gi` \~14 GiB. Setzen Sie `requests.memory` auch auf einen echten Boden, damit der Scheduler es reserviert. Das Anwenden **erstellt den CH-Pod neu** (einzelnes Replikat → \~30–60s Analytics-Ausfallzeit); tun Sie es in einem Zeitfenster mit geringem Traffic.
2. Halten Sie die Caches in `deploy/base/clickhouse/configmap.yaml` proportional zum Limit – kleine Caches (ein paar hundert MiB) sind auf einem kleinen Pod sicher; erhöhen Sie sie nur zusammen mit einer entsprechenden Speicherlimit-Erhöhung. Pro-Query-`max_memory_usage` ist explizit im `users.xml`-Profil gesetzt (siehe den Fixed-Node-Abschnitt unten) und wird unter der server-level-Obergrenze (`0,9 × Limit`) gehalten, sodass keine einzelne Query mehr RAM haben kann als der Container.
3. Wenn der Knoten selbst die Obergrenze ist, prüfen Sie den Host-Speicher, den ClickHouse sehen kann:
   ```bash theme={null}
   kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
     "SELECT formatReadableSize(value) FROM system.asynchronous_metrics WHERE metric='OSMemoryTotal'"
   ```
   Wenn das nur etwas über dem Pod-Limit liegt, verschieben Sie ClickHouse auf einen größeren (speicheroptimierten) Knoten – über einen Node-Selector/Affinity in Ihrem Overlay – bevor Sie das Limit weiter erhöhen.

**Wenn Sie keinen Speicher hinzufügen können: Queries im RAM halten und schnell abbrechen – nicht auf langsamer Festplatte spilten.** Wenn der Knoten fest und der Pod nicht wachsen kann, begrenzen Sie, was eine einzelne Query verwenden darf (damit eine Query nicht den gesamten Knoten übernehmen kann) und lassen Sie auf einer **langsamen (Nicht-SSD) Datenfestplatte** große Aggregationen/Sortierungen **nicht** auf die Festplatte spillen. Das Spillen auf eine langsame Festplatte ist langsamer als der Client-Read-Timeout des Servers, sodass eine spillende Query ein Dashboard-`500` mitten im Flug zurückgibt, während ClickHouse weiter arbeitet – Queries im RAM zu halten und das seltene über-Budget-Query *schnell* abzulehnen (`MEMORY_LIMIT_EXCEEDED`, unter einer Sekunde) stellt das Laden wieder her. Hinweis auf eine ClickHouse-Tücke beim Anwenden:

* **Dies sind *Profil*-Einstellungen, und ClickHouse liest `<profiles>` nur aus `users_config` (`users.xml` / `users.d/*.xml`) – niemals aus `config.d`.** Ein `<profiles>`-Block in `config.d/agenteye.xml` wird **lautlos ignoriert** (`max_execution_time`, `max_memory_usage` usw. werden einfach nicht angewendet). Die gebündelte Konfiguration liefert sie daher als `users.xml`-Schlüssel auf der `clickhouse-config`-ConfigMap, eingebunden unter `/etc/clickhouse-server/users.d/agenteye.xml`.
* Die mitgelieferten Standardwerte: `max_memory_usage` (Pro-Query-Obergrenze – eine Query kann nicht das gesamte Server-Budget verbrauchen), `max_bytes_before_external_group_by` / `max_bytes_before_external_sort` = **`0` (Spill deaktiviert)**, damit Queries im RAM bleiben statt auf der langsamen Festplatte zu kriechen, und `max_execution_time` (Ausreißer-Wächter, abgestimmt auf den Client-Read-Timeout des Servers).
* **Prüfen Sie, ob sie aktiv sind** (so erkennen Sie auch die config.d-Tücke):
  ```bash theme={null}
  kubectl -n agenteye exec clickhouse-0 -- clickhouse-client -q \
    "SELECT name, value FROM system.settings
     WHERE name IN ('max_memory_usage','max_bytes_before_external_group_by','max_execution_time')"
  ```
  Erwarten Sie einen von Null verschiedenen `max_memory_usage` und `max_bytes_before_external_group_by = 0`. Wenn `max_memory_usage` `0`/Standard liest, wird das Profil nicht angewendet – prüfen Sie, ob die Einstellungen in einem `users.d`-Mount leben, nicht in `config.d`.

Trade-off: Mit deaktiviertem Spill wird eine Query, deren Working Set `max_memory_usage` überschreitet, **abgelehnt** (`MEMORY_LIMIT_EXCEEDED`) statt langsam abzuschließen – auf einer langsamen Festplatte ist diese schnelle Ablehnung vorzuziehen, da eine spillende Query den Client-Timeout überschreiten und trotzdem scheitern würde. Wenn Ihre Datenfestplatte **schnell (SSD)** ist, können Sie stattdessen die `max_bytes_before_external_*`-Schwellenwerte erhöhen, um großen Queries das Spillen auf die Festplatte und das Abschließen zu ermöglichen.

***

## Multi-Tenancy (Organisationen)

### Fehler beim Upgrade, das Organisationen aktiviert (gemischte alte/neue Server-Pods)

**Symptom:** Während eines Rolling-Deploys des org-aktivierenden Release schlagen einige Anfragen fehl: Server-Logs zeigen `there is no unique or exclusion constraint matching the ON CONFLICT specification` auf dem `api_keys`-Pfad, und/oder Alert-/Slack-/Webhook-Kanäle hören während des Rollouts auf zu feuern.

**Ursache:** Das Upgrade ersetzt den alten instanzweiten eindeutigen Index auf `api_keys(name)` durch organisationsspezifische Partial-Indexes und verschiebt die Alert-Kanal-Einstellungen (und `default_user_permissions`) aus der globalen `settings`-Tabelle in pro-org `org_settings`. Ein **alter** Server-Pod gibt noch `ON CONFLICT (name)` aus (jetzt keine passende Einschränkung) und liest noch Kanal-Konfiguration aus den alten `settings`-Zeilen (jetzt leer). Alte und neue Pods können für diese beiden Pfade nicht sicher koexistieren.

**Lösung:** Rollen Sie dieses bestimmte Upgrade nicht langsam über gemischte Versionen. Führen Sie einen sauberen Cutover durch: Skalieren Sie den alten Server auf null (oder nutzen Sie ein kurzes Wartungsfenster) und bringen Sie die neue Version zusammen mit ihren Migrationen hoch, anstatt alte und neue Replikas nebeneinander zu betreiben. Normaler Traffic und Ingest werden unmittelbar nach dem Cutover wieder aufgenommen; dies betrifft nur das Versions-Übergangsfenster.

### Bereitstellung einer Organisation schlägt auf `CREATE USER` / `CREATE ROW POLICY` fehl, oder eine Org kann Daten einer anderen Org lesen

**Symptom:** Das Erstellen einer Org gibt einen Fehler zurück, der `CREATE USER`, `CREATE ROW POLICY` oder "access management is disabled" erwähnt; oder, schlimmer, Mitglieder einer Org sehen Ereignisse/Evaluierungen einer anderen Org im SQL-Editor oder Assistenten.

**Ursache:** Die pro-org-Isolation wird durch einen dedizierten ClickHouse-Benutzer + Row Policy pro Org durchgesetzt. Dies erfordert, dass SQL **Access Management** aktiviert und `users_without_row_policies_can_read_rows=false` auf ClickHouse gesetzt ist. Mit deaktiviertem Access Management kann die Bereitstellung den Benutzer/die Policy nicht erstellen; mit dem Row-Policy-Standard bei seinem permissiven Wert liest ein Benutzer, der SELECT aber keine Policy hat, **alle** Zeilen (fail-open).

**Lösung:** Verwenden Sie die gebündelte `deploy/base/clickhouse/`-Konfiguration, die beides setzt. Wenn Sie Ihre eigene ClickHouse-Konfiguration betreiben, aktivieren Sie SQL Access Management für den server-internen Benutzer und setzen Sie `users_without_row_policies_can_read_rows=false` (siehe `deploy/base/clickhouse/configmap.yaml`), starten Sie dann ClickHouse neu und erstellen Sie die Org mit der `agenteye-orgctl`-CLI neu (siehe [enterprise-docs/tenant-management.md](/de/agenteye/tenant-management)).

### Org-Benutzer verlieren ClickHouse-Zugriff nach Änderung von `ORG_CH_SECRET`

**Symptom:** Der SQL-Editor und der KI-Assistent geben plötzlich ClickHouse-Authentifizierungsfehler für jede Organisation zurück, unmittelbar nachdem `ORG_CH_SECRET` geändert wurde oder inkonsistent über Replikas gesetzt war.

**Ursache:** Das ClickHouse-Passwort jeder Org wird als HMAC von `ORG_CH_SECRET` abgeleitet. Das Rotieren (oder das Ausführen von Replikas mit unterschiedlichen Werten) macht die gespeicherten ClickHouse-Anmeldeinformationen jeder Org ungültig; das abgeleitete Passwort stimmt nicht mehr mit dem bereitgestellten Benutzer überein.

**Lösung:** Setzen Sie `ORG_CH_SECRET` auf einen einzigen starken Wert **vor** der Bereitstellung einer zweiten Org und halten Sie ihn stabil und identisch auf jedem Server-Replikat. Die Server-Boot-Zeit-Abstimmung stellt beim Start den ClickHouse-Benutzer jeder Org aus dem aktuellen Secret wieder her, sodass ein Server-Neustart über alle Replikas (mit konsistentem Secret) die verwaisten Benutzer heilt. Behandeln Sie den Wert als ein langlebiges Secret; rotieren Sie ihn nicht leichtfertig. Als Sicherheitsnetz gilt: Wenn `ORG_CH_SECRET` beim eingebauten Dev-Standard bleibt (d. h. nicht gesetzt ist), **überspringt** die Boot-Zeit-Abstimmung Nicht-Standard-Organisationen und protokolliert einen Fehler statt ihre ClickHouse-Anmeldeinformationen auf den öffentlich bekannten Dev-Wert umzuschreiben, sodass ein einzelnes Replikat, das ohne das Secret neu startet, die anderen Replikas nicht brechen kann. Setzen Sie das Secret konsistent und starten Sie neu, um diese Orgs bereitzustellen.

### Der KI-Assistent gibt 400 zurück / weigert sich zu chatten nach Aktivierung von Organisationen

**Symptom:** Das Assistent-Dock lädt, aber jede Nachricht kommt als Fehler zurück (HTTP `400`), und der Agent protokolliert eine abgelehnte org-lose `/chat`-Anfrage.

**Ursache:** Der Agent ist org-bewusst und schlägt geschlossen fehl; er lehnt ein `/chat` ab, das keinen Organisationskontext enthält. Dies geschieht während eines Übergangs-Rollouts, bei dem der Agent aktualisiert wurde, aber das Dashboard, das die Anfrage sendet, noch nicht org-bewusst ist.

**Lösung:** Schließen Sie das Rollout ab, sodass das Dashboard Org-Kontext sendet (der normale Endzustand, kein Flag erforderlich). Um die Lücke zu überbrücken, während ein noch-nicht-org-bewusstes Dashboard mit einem org-bewussten Agent spricht, setzen Sie `AGENTEYE_AGENT_ALLOW_NO_ORG=1` am `agent`-Dienst, sodass er auf die `default`-Org zurückfällt statt abzulehnen, und entfernen Sie es, sobald das Dashboard-Upgrade landet. Siehe die Env-Referenz in [enterprise-docs/assistant.md](/de/agenteye/assistant#environment-variable-reference).

***

## Audits

### Ein Audit läuft nie (nächster Lauf verschiebt sich ständig, keine Laufhistorie)

**Symptom:** Die Audit-Seite zeigt *last run: never* an, oder `next run` bewegt sich immer weiter in die Zukunft, ohne dass eine Zeile in der Laufhistorie erscheint.

**Ursache:** Das Audit ist deaktiviert (deaktivierte Audits haben keinen Warteschlangeneintrag), oder die Audit-Worker des Servers schlagen beim Beanspruchen von Arbeit fehl.

**Lösung:** Bestätigen Sie, dass das Audit **aktiviert** ist (die Run-Now-Schaltfläche erfordert es). Prüfen Sie dann die Server-Logs auf `audits pipeline started` beim Start und auf `audits:`-Fehler – eine `claim_due failed`-Zeile verweist auf Postgres-Konnektivität. `AUDIT_WORKERS` ist standardmäßig `1`; es muss ≥ 1 sein, damit ein Audit läuft.

### Audit-Läufe erfolgreich, finden aber nichts

**Symptom:** Die Laufhistorie zeigt `succeeded` mit `findings: 0`, obwohl `/errors` deutlich Fehler zeigt.

**Ursache:** Das Scan-Fenster deckt die Fehler nicht ab, oder die Scope-Filter schließen sie aus.

**Lösung:** Prüfen Sie das Lauf-Zeilenfeld (\`
