OPENCLAW MACOS
STALE_
LAUNCHAGENT_
TOKEN.
Sur la branche 2026.4.x, on voit souvent : vous émettez un nouveau jeton Gateway via doctor ou la console, vous exportez la valeur dans zsh, peut-être même dans Docker Compose — et pourtant Telegram, IM d’entreprise, l’UI Web et les clients d’intégration répondent tous 401 unauthorized. Localement, openclaw gateway status peut rester vert brièvement parce que la sonde est plus courte qu’un vrai message canal. Or LaunchAgent macOS injecte encore OPENCLAW_GATEWAY_TOKEN depuis la EnvironmentVariables de la plist. Sans --force, openclaw gateway install peut afficher « déjà installé » et ne pas réécrire la plist. Cet article propose une matrice symptômes/preuves, une triple vérif (plist / shell / coffre), bootout–édition–bootstrap, réinstallation forcée, contrôles SSH Mac headless et gates incident. Croisez avec breaking & auth v2, Docker / WS, migration launchd, Gateway silencieux, systemd / launchd.
1. Pourquoi 401 globaux coexistent avec un processus vivant
Le transport peut être sain pendant que l’authentification échoue : le Gateway écoute mais rejette les en-têtes avec l’ancien secret. Les plugins canal surfacent l’erreur ; les sondes légères, pas toujours. launchd n’hérite pas de votre dernière session interactive. Si le plan de contrôle révoque l’ancien jeton, toutes les routes broker tombent jusqu’à alignement plist. L’installateur idempotent est une fonctionnalité — pas un remplacement de secret tant que vous n’activez pas la sémantique d’écrasement (--force selon l’aide CLI).
2. Matrice symptôme / preuve
| Observation | Hypothèse | Preuve |
|---|---|---|
| Tous les canaux 401 à la même minute | Gateway tient un jeton révoqué | horodatage + corps HTTP d’échec |
| échec launchd seulement, premier plan OK | plist obsolète | plutil -p ~/Library/LaunchAgents/*openclaw*.plist |
| install « réussi », pas de fix | aucune écriture plist | mtime/hash avant-après |
| uniquement Mac distant | mauvais utilisateur ou domaine launchd | launchctl print gui/$(id -u) |
3. Comment LaunchAgent amplifie l’oubli
La plist est une infrastructure déclarative : la chaîne sérialisée survit aux reboots tant qu’on ne fait pas bootout, modifier, recharger. Traitez la rotation comme une mini-release : secret coffre → toutes les matérialisations (plist, compose) → redémarrage Gateway → smoke métier réel (message canal), pas seulement curl local.
4. Sept étapes
Étape 01 — gel
Versions CLI, label LaunchAgent, horaire de rotation ; évitez deux redémarrages concurrents non coordonnés.
Étape 02 — trouver la plist
~/Library/LaunchAgents/ ; utilisateur dédié ⇒ son $HOME.
Étape 03 — trois sources
plist, shell (contexte), empreinte coffre — jamais de secrets en clair dans le chat.
Étape 04 — bootout / édition / bootstrap
Domaine et label selon doc officielle.
Étape 05 — force
openclaw gateway install --force si l’aide le permet ; critère d’acceptation : métadonnées plist modifiées.
Étape 06 — validation en couches
logs sains → round-trip canal réel → UI ; chercher une seconde plist ou un doublon Docker.
Étape 07 — hygiène
révoquer l’ancien jeton, chiffrer les sauvegardes, préférer trousseau ou fichier 0600.
5. Mac distant : dix points SSH
même utilisateur Unix, $HOME, launchctl print, chemin ProgramArguments, anciens chemins post-migration, pare-feu minimal, connexion Aqua requise ou non, droits des logs, priorité Docker vs launchd (guide Docker), journaux masqués dans le ticket.
Gates
A : sous 10 minutes après rotation, mtime plist modifiée ou install forcé documenté. B : au moins une transaction non-sonde réussie. C : jeton remplacé marqué revoked dans le coffre.
6. Idées reçues
Modifier seulement .env pendant que launchd possède le service ne suffit pas. Un message vert d’install sans toucher la plist n’est pas un alignement. Curl loopback ne prouve pas les webhooks Telegram.
7. Frontière upgrade / migration
Les breaking bougent identité appareil et attestation. Doctor sans plist donne un état « à moitié vert ». Convergez vers un seul pipeline de secrets avec le runbook migration.
8. Chronologie incident (0–30 minutes)
T+0–2 min : geler les installs concurrentes, épingler label + build. T+3–8 min : corréler corps 401 et ligne auth ; si seuls les clients crient, suspectez proxy/port fantôme. T+9–15 min : plist, Compose éventuel, coffre — deux vérités = dérive. T+16–25 min : bootout → correctif ou force → bootstrap ; un seul ordre de bascule par incident. T+26–30 min : pas d’all-clear sans gates. Les Mac rack headless n’ont pas d’épaule à taper : le runbook écrit fixe le MTTR.
9. Double passerelle, ports, reverse-proxy
Débogage premier plan vs launchd sur ports différents, TLS neuf mais proxy_pass ancien, Docker ajoutant une troisième couche : tout ressemble à « token juste, 401 persistant ». Mesurez build/commit sur loopback et FQDN ; hashes identiques. Un seul superviseur (launchd ou compose) ou dual-write obligatoire dans chaque RFC.
10. Triangle plist ↔ launchctl ↔ processus
| Couche | Sain | Cassé |
|---|---|---|
| Fichier | mtime bouge, plutil ok | XML cassé, droits |
| launchctl | chemin = which | préfixe nvm mort |
| Env process | empreinte = coffre | démarrage sans clé |
| Journaux | 401 = refus auth | CPU seule — jsonl/bootstrap d’abord |
Ne transposez pas aveuglément EnvironmentFile systemd : les LaunchAgents macOS aiment les littéraux XML. Sans triangle, l’équipe remote erre.
11. FAQ branches sournoises
Q : plist modifiée, toujours 401. R : chemin réel via launchctl print, pas une copie iCloud. Q : révoquer avant redémarrage ? R : ordre documenté seulement. Q : doctor vert, IM rouge. R : boucle message réelle obligatoire. Q : mini multi-utilisateur ? R : comptes Unix séparés.
12. Conclusion
Les 401 universels après rotation sont presque toujours une dérive de configuration. Pour de l’Apple Silicon toujours allumé : tarifs MACGPU, Telegram (mot-clé MACGPU). Référence finale : aide CLI officielle de votre version.