Ich habe eine fertige JSON-Konfiguration auf einen selbst gehosteten Dienst geschoben, neu gestartet — und die Hälfte davon war wirkungslos. Die Datei war nicht kaputt. Sie war für eine andere Version geschrieben.
Die Online-Doku eines Projekts beschreibt immer den aktuellen Stand. Auf deinem Server läuft der Stand vom Tag der Installation. Bei OpenClaw liegen zwischen meiner installierten Version und dem aktuellen npm-Stand fünf Monate Schema-Änderungen. Einen Schlüssel, den die Doku heute ausdrücklich empfiehlt, kennt meine Version noch gar nicht.
Du kannst das vorher prüfen, ohne den laufenden Dienst anzufassen. Das Muster funktioniert bei jedem Node-Tool, das seine Konfiguration schema-validiert und einen config get-Befehl mitbringt.
Getestet mit
- openclaw 2026.2.6 (die installierte Version)
- openclaw 2026.7.1-2 (aktuellster npm-Stand, nur zum Vergleich)
- Node.js 22.23.2 — openclaw verlangt ab 2026.2.6 mindestens 22.12.0
- npm 10.9.8
- Debian, Docker-Container ohne Docker-Socket
Schritt 1: Die Version feststellen, die wirklich läuft
Nicht die aus dem Changelog, nicht die aus deiner Erinnerung. Die aus dem Container.
docker exec -it DEIN-CONTAINER openclaw --version
# 2026.2.6
Wenn der Dienst hinter einem Panel wie Coolify läuft, findest du dieselbe Nummer im Image-Tag. Nimm die exakte Nummer, nicht „ungefähr Februar“.
Schritt 2: Dieselbe Version daneben installieren
Nicht auf dem Server. Irgendwo, wo nichts kaputtgehen kann — dein Rechner, eine leere VM, ein Wegwerf-Verzeichnis.
mkdir -p /tmp/oc-check && cd /tmp/oc-check
npm init -y
npm install openclaw@2026.2.6 --no-audit --no-fund
Das dauert bei mir knapp 50 Sekunden und zieht 627 Pakete. Du startest nichts davon, du benutzt nur den Validator.
Schritt 3: Die Config als Datei ablegen
Schreib die Konfiguration, die du einspielen willst, in eine Datei. Platzhalter statt echter Token — der Validator prüft die Struktur, nicht die Gültigkeit der Zugangsdaten.
cat > /tmp/oc-check/openclaw.json <<'EOF'
{
"channels": {
"telegram": {
"defaultAccount": "default",
"accounts": {
"zweitbot": {
"token": "ZWEITER-BOT-TOKEN",
"allowedIds": ["DEINE-TELEGRAM-ID"]
}
}
}
},
"agents": {
"entries": {
"zweit": { "workspace": "/data/workspace-zweit" }
}
},
"bindings": [
{ "agentId": "zweit", "match": { "provider": "telegram", "accountId": "zweitbot" } }
]
}
EOF
Das ist bewusst die Fassung, die ich aus der Doku und aus dem Bauch heraus gebaut hatte. Sie sieht richtig aus.
Schritt 4: Validieren, ohne etwas zu starten
Der entscheidende Befehl. config get liest die Datei aus OPENCLAW_CONFIG_PATH, prüft sie gegen das Schema der installierten Version und gibt danach den angefragten Teilbaum aus.
cd /tmp/oc-check
OPENCLAW_CONFIG_PATH=/tmp/oc-check/openclaw.json
node node_modules/openclaw/openclaw.mjs config get agents.list
Bei meiner Fassung von oben kommt das hier:
Config invalid
File: /tmp/oc-check/openclaw.json
Problem:
- agents: Unrecognized key: "entries"
- bindings.0.match.channel: Invalid input: expected string, received undefined
- bindings.0.match: Unrecognized key: "provider"
- channels.telegram.accounts.zweitbot: Unrecognized keys: "token", "allowedIds"
- channels.telegram: Unrecognized key: "defaultAccount"
Run: openclaw doctor --fix
Fünf Meldungen aus einer Datei, die auf dem Server ohne einen einzigen Hinweis durchgelaufen wäre. Der Validator gibt alle auf einmal aus, nicht nur die erste — du arbeitest sie in einem Durchgang ab.
Schritt 5: Korrigieren, bis nichts mehr gemeldet wird
Die richtigen Namen stehen nicht online, sondern in der Doku, die im installierten Paket liegt: node_modules/openclaw/docs/. Die gehört zur Version, die du geprüft hast.
cat > /tmp/oc-check/openclaw.json <<'EOF'
{
"channels": {
"telegram": {
"botToken": "HAUPT-BOT-TOKEN",
"dmPolicy": "allowlist",
"allowFrom": ["DEINE-TELEGRAM-ID"],
"accounts": {
"zweitbot": {
"botToken": "ZWEITER-BOT-TOKEN",
"name": "Zweitbot",
"dmPolicy": "allowlist",
"allowFrom": ["DEINE-TELEGRAM-ID"],
"groupPolicy": "disabled"
}
}
}
},
"agents": {
"list": [
{
"id": "zweit",
"name": "Zweitagent",
"workspace": "/data/workspace-zweit",
"tools": { "allow": ["read", "write", "exec"], "deny": ["browser"] }
}
]
},
"bindings": [
{ "agentId": "zweit", "match": { "channel": "telegram", "accountId": "zweitbot" } },
{ "agentId": "main", "match": { "channel": "telegram", "accountId": "default" } }
]
}
EOF
Vier Unterschiede zur ersten Fassung: agents.list ist ein Array mit id, nicht ein Objekt agents.entries. Der Token heißt botToken. Die Allowlist heißt allowFrom. Und im Binding heißt das Feld channel, nicht provider.
Der Schlüssel aus der Doku, den meine Version nicht kannte
channels.telegram.defaultAccount war der Eintrag, an dem ich am längsten gesessen bin. Er steht in der Doku, er ist dort sogar ausdrücklich empfohlen, sobald du mehr als einen Account konfigurierst. Meine Version wirft ihn als unbekannten Schlüssel raus.
Ich habe zuerst an einem Tippfehler gesucht, dann an der Verschachtelung. Gefunden habe ich es über den Vergleich der beiden Pakete:
npm pack openclaw@2026.7.1-2
tar xzf openclaw-2026.7.1-2.tgz
grep -rn "defaultAccount" package/docs/channels/telegram.md
# Treffer
npm pack openclaw@2026.2.6
tar xzf openclaw-2026.2.6.tgz
grep -rn "defaultAccount" package/docs/channels/telegram.md
# nichts
Der Schlüssel ist zwischen den beiden Versionen dazugekommen. Ich hatte die Doku der einen gelesen und gegen das Schema der anderen geschrieben.
Noch unangenehmer war match.provider. Das stammt nicht aus der Online-Doku, sondern aus docs/multi-agent-sandbox-tools.md — der Doku, die im installierten Paket 2026.2.6 selbst liegt. Dort steht ein vollständiges Binding-Beispiel mit "provider": "whatsapp", und genau dieses Beispiel lehnt der Validator derselben Version ab. Ein Verzeichnis weiter, in docs/concepts/multi-agent.md, steht es richtig mit channel. In der aktuellen Version ist die falsche Stelle bereinigt.
Seitdem prüfe ich zuerst gegen das Schema und erst danach gegen ein Doku-Beispiel. Ein Beispiel kann veraltet sein, auch wenn es mitgeliefert wird. Das Schema ist der Code, der die Datei am Ende liest.
Kontrolle
Wenn die Datei sauber ist, verschwindet der Block „Unknown config keys“ komplett, und config get gibt den Teilbaum als JSON aus:
OPENCLAW_CONFIG_PATH=/tmp/oc-check/openclaw.json
node node_modules/openclaw/openclaw.mjs config get bindings
[
{
"agentId": "zweit",
"match": {
"channel": "telegram",
"accountId": "zweitbot"
}
},
{
"agentId": "main",
"match": {
"channel": "telegram",
"accountId": "default"
}
}
]
Kommt das JSON zurück und steht darüber kein Fehlerblock, kannst du die Datei auf den Server legen. Was config get ausgibt, ist der Wert nach der Validierung — also das, was der Dienst tatsächlich sehen wird.
Häufige Fehler
Ich habe das Paket mit npm pack entpackt und bekomme Cannot find package 'chalk'. npm pack lädt nur das Paket selbst, ohne Abhängigkeiten. Zum Ausführen brauchst du npm install openclaw@VERSION in einem eigenen Verzeichnis. Zum reinen Nachlesen der mitgelieferten Doku reicht npm pack dagegen aus, und das geht deutlich schneller.
Der Validator meldet nichts, aber eine Einstellung greift trotzdem nicht. Dann ist der Schlüssel gültig und wird nur woanders überschrieben. Gib gezielt den Pfad aus: config get channels.telegram.dmPolicy statt config get channels. Steht dort ein anderer Wert als in deiner Datei, gewinnt eine Umgebungsvariable oder ein Default.
Kann ich das direkt auf dem Server machen? Kannst du, wenn du dort ein Verzeichnis mit Schreibrechten hast und den Pfad über OPENCLAW_CONFIG_PATH auf die Testdatei zeigen lässt. Ich mache es lieber daneben, weil ein versehentlich falsch gesetzter Pfad sonst die echte Config trifft.
Warum nicht einfach doctor --fix laufen lassen? Weil --fix unbekannte Schlüssel entfernt. Bei einer Config, deren Hälfte aus zu neuen Schlüsseln besteht, bleibt danach eine Datei übrig, die zwar validiert, aber nicht mehr das tut, was du wolltest. Erst verstehen, warum ein Schlüssel unbekannt ist, dann korrigieren.