Plugin-Troubleshooting

Manifest-, Codegen-, Host- und Laufzeitfehler — was jeder einzelne bedeutet und wie Sie ihn beheben.

Plugin-Fehler sind bewusst laut und brechen fail-closed ab. Nahezu jeder fällt in eine von vier Familien: Das Manifest ist ungültig, die Komposition ist ungültig oder veraltet, die Autorisierung wurde verweigert, oder eine Contribution ist in ihren deklarierten sicheren Fallback gelaufen.

Manifest-Fehler

definePlugin und parsePluginManifest werfen PluginManifestError mit einem Issue je Problem: { code, path, message }, wobei path ein JSON-Pointer-ähnlicher String wie $.contributes.crons[0].timeoutMs ist. validatePluginManifest liefert dieselben Issues zurück, ohne zu werfen.

Issue-CodeTypische Ursache
missingEin Pflichtfeld fehlt — meist $.flag bei einem Plugin, das Contributions liefert, Storage nutzt oder llm:invoke anfordert; oder in $.capabilities fehlt die Capability, die ein deklarierter Bucket voraussetzt
invalid_typeFalscher JavaScript-Typ oder eine Accessor-Property dort, wo Daten verlangt waren
invalid_formatid ist nicht kleingeschriebenes Kebab-Case mit ≤ 64 Zeichen, version ist kein Semver, eine Capability ist nicht domain:action, eine Umgebungsvariable ist nicht UPPER_SNAKE, oder ein Export-Pfad ist kein sicherer relativer Package-Export
duplicateEine wiederholte Capability oder eine wiederholte erforderliche Umgebungsvariable
unknown_fieldEin Feld oder Contribution-Bucket, den die Plattform nicht kennt
too_many_itemsÜber einer Obergrenze: 64 Capabilities, 64 Umgebungsvariablen, 256 Einträge pro Bucket, 64 Settings-Felder
accessor_not_allowedEin Getter/Setter dort, wo der Validator reine Daten verlangt — Manifeste werden als Daten inspiziert und niemals aufgerufen

Häufige Anfängerfehler:

  • "must declare <capability> when <nouns> are contributed" — fügen Sie die Capability-Konstante zu capabilities hinzu.
  • "$.flag must be a plain object when …" — jeder Contribution-Bucket, beide Storage-Capabilities und llm:invoke erfordern ein explizites flag.
  • llmBudget abgelehntdailyUsd muss > 0 und ≤ 1 000 000 sein und mit höchstens sechs Nachkommastellen darstellbar sein.
  • Cron abgelehntintervalMinutes muss zwischen 15 und 40 320 liegen und timeoutMs zwischen 1 000 und 300 000.
  • "must be listed in $.flag.requiredEnvVars" — das signature.secretEnvVar eines Feedback-Webhooks muss zusätzlich in flag.requiredEnvVars auftauchen. Ohne das Secret kann die Route nur mit 503 antworten, und durch das Auflisten wird das Plugin so lange nicht aktivierbar, bis ein Operator es setzt.

Codegen-Fehler

PluginCodegenError trägt einen Code plus eine Detailliste.

CodeBedeutung und Behebung
config_invalidplugins.config.ts ist keine literale Liste von Package-Namen. Sie wird als Daten geparst, niemals ausgewertet — belassen Sie sie als einfaches Array
dependency_missing"Bundled plugin <name> must be installed as a root dependency or optionalDependency." Installieren Sie es im Workspace-Root aus der Registry und führen Sie dann add erneut aus
dependency_provenanceInstallierte Metadaten, die Integrität von bun.lock oder die Realpath-Eingrenzung haben nicht übereingestimmt. Aliase sowie git-/URL-/file-/workspace-Quellen scheitern per Design fail-closed
package_load_failedDer Manifest-Eintrag des Packages konnte nicht importiert werden. Prüfen Sie, dass der Default-Export das definePlugin-Manifest ist und dass sein Import keine Seiteneffekte hat
conditional_manifest_exportDer Manifest-Export ist bedingungsabhängig, sodass Bun, Convex, Nuxt-SSR und der Browser-Build unterschiedliche Manifeste auflösen könnten. Verwenden Sie einen einzigen bedingungsunabhängigen Root-Export
invalid_manifestDas geladene Manifest hat die Validierung nicht bestanden — siehe die Manifest-Tabelle oben
component_export_invalid / contribution_export_invalidEin deklarierter exportPath ist kein exakter, existierender, bedingungsunabhängiger Package-Export
composition_invalidDoppelte Package-Namen, doppelte Manifest-Ids oder ein Contribution-Graph, den der Host ablehnt (unbekannter oder terminaler Agent-Step-Anker, doppelte Art, Einfügezyklus, unsichere Lifecycle-Kante)
generated_files_stale--check hat fehlende oder veraltete Ausgabe gefunden. Führen Sie bun run plugins:codegen aus und committen Sie das Ergebnis zusammen mit der Konfigurationsänderung
generated_path_unsafeEin generiertes Ziel oder ein übergeordnetes Verzeichnis ist ein Symlink. Die Ausgabe wird über eine exklusive temporäre Datei und ein atomares Rename geschrieben und folgt Links grundsätzlich nicht
direct_plugin_importCore-Quellcode importiert ein konfiguriertes Plugin-Package außerhalb der generierten Kompositionsdateien — auch über einen Node-/Bun-Loader oder einen Repository-Alias. Leiten Sie den Import über die generierte Registry
repository_inventory_invalidDer Boundary-Scan konnte sein begrenztes Datei-Inventar nicht aufbauen, oder das Repository überschreitet das Datei-Sicherheitslimit des Scans
repository_config_invalidEine Repository-Alias-Konfiguration (tsconfig-Paths, Bundler-Aliase) konnte nicht sicher gelesen werden, oder die Alias-Erkennung hat ihr Dateilimit überschritten
source_invalidEine Quelldatei konnte beim Scannen für die Import-Boundary-Regel nicht geparst werden
workspace_not_foundDer Befehl wurde außerhalb des Owlat-Workspace ausgeführt
Führen Sie die CLI aus einem vorbereiteten Workspace aus

Cannot find module '@owlat/plugin-kit' beim Aufruf der CLI oder der Codegen aus dem Quellcode bedeutet, dass die Contracts noch nicht gebaut wurden. Führen Sie einmal bun run plugins:prepare aus (die Skripte plugins:codegen / plugins:check erledigen das für Sie).

Dasselbe gilt, wenn Sie die Tests von packages/plugin-codegen oder packages/plugin-cli direkt mit vitest ausführen. Diese Packages bauen die Contracts bewusst nicht selbst neu: packages/plugin-kit/dist ist ein gemeinsam genutztes Artefakt, das mit tsup --clean neu gebaut wird, sodass ein package-lokaler Rebuild es unter allem anderen wegräumen würde, was der Lauf gerade kompiliert. Stattdessen besitzt Turbo diese Reihenfolge (test hängt von @owlat/plugin-kit#build ab), und bun run lint:build-graph schlägt fehl, wenn ein Package-Skript wieder anfängt, es neu zu bauen.

Dieser Schutz deckt auch packages/plugin-kit selbst ab — nur dessen build sowie die ausschließlich fürs Publishing gedachten Hooks prepack / postpack dürfen tsup --clean antreiben, weshalb der Package-Smoke-Test mit --ignore-scripts packt und prüft, dass dist/ unberührt geblieben ist — sowie das Repository-Root, wo plugins:prepare der eine sanktionierte Einstiegspunkt ist: Jedes andere Root-Skript, das mit --cwd in ein anderes Workspace-Verzeichnis greift, lässt den Schutz fehlschlagen, sofern es nicht in ROOT_CWD_ALLOWLIST in scripts/check-build-graph.ts aufgenommen wird.

Host-Ablehnungen

PluginHostError wird an der Enforcement-Grenze ausgelöst. Sein Code sagt genau, welches Glied der Kette gerissen ist.

CodeBedeutungBehebung
capability_not_declaredDas Manifest hat diese Capability nie angefordertFügen Sie sie dem Manifest hinzu und deployen Sie neu — eine Gewährung kann ein Manifest nicht erweitern
capability_not_grantedDeklariert, aber der Operator hat sie nicht gewährtAktivieren Sie das Plugin und genehmigen Sie seine Capabilities unter Einstellungen → Plugins
plugin_disabledDas Feature-Flag ist ausAktivieren Sie das Flag
required_environment_missingEine Variable aus flag.requiredEnvVars fehltSetzen Sie sie in der Deployment-Umgebung; die Aktivierung ist blockiert, bis jede einzelne vorhanden ist
environment_check_failed / feature_check_failedDer Host konnte die Umgebung oder das Flag nicht auswertenInfrastrukturproblem — die Operation bricht fail-closed ab, was so gewollt ist
invalid_capability_grant / invalid_manifest_snapshot / invalid_contributionHost-Konfiguration oder Komposition sind inkonsistentFühren Sie die Codegen erneut aus; bleibt es bestehen, sind Komposition und Deployment auseinandergedriftet
untrusted_output_rejectedEin Plugin hat an einer Textgrenze etwas anderes als einen String zurückgegeben, oder der Scrubber ist fehlgeschlagenGeben Sie aus dem Modul einen einfachen String zurück
invalid_untrusted_text_policyEin Host-Adapter hat eine ungültige Policy benanntHost-Bug, kein Plugin-Bug

"Meine Contribution läuft nicht"

Arbeiten Sie diese Liste ab — es ist dieselbe Reihenfolge, in der der Host prüft:

  1. Ist das Package in plugins.config.ts eingetragen und ist die generierte Komposition aktuell (bun run plugins:check)?
  2. Wurde das Deployment nach der Konfigurationsänderung neu gebaut? Die gebündelte Komposition ist ein Build-Zeit-Artefakt.
  3. Ist das Feature-Flag des Plugins aktiviert?
  4. Wurden seine Capabilities bei der Aktivierung genehmigt? Das Deaktivieren löscht den Gewährungsdatensatz.
  5. Sind alle flag.requiredEnvVars in der Deployment-Umgebung vorhanden?
  6. Deklariert das Manifest die Capability, die der Bucket voraussetzt?
  7. Bei Navigations- und Einstellungseinträgen: Existiert der Zielabschnitt und ist er feature-seitig aktiv? Besitzt bereits ein anderer Eintrag denselben href? Die Deduplizierung läuft über href, der zuerst registrierte gewinnt, und Core registriert zuerst.

"Die Contribution lief, aber nichts hat sich geändert"

Das ist meist ein sicherer Fallback, der seine Arbeit tut. Jeder Bucket hat eine deklarierte Richtung:

SymptomWahrscheinliche Ursache
Antworten gehen weiterhin in die menschliche PrüfungEin Plugin-Gate hat Einspruch erhoben, ist in ein Timeout gelaufen, hat geworfen, fehlerhafte Ausgabe geliefert oder wurde abgewiesen. Gates brechen fail-closed ab
Drafts sehen aus wie die eingebautenDie Draft-Strategie des Plugins wurde abgewiesen, lief in ein Timeout, schlug fehl oder erzeugte übergroße bzw. injektionsartige Ausgabe — ein Rückfall auf default
Ein Agent-Step ist aus der Pipeline verschwundenDie Autorisierung wurde im letzten Moment verweigert. Der Walker überspringt die Contribution und setzt die unveränderte Core-Fortsetzung fort
Ein Automations-Step wiederholt sich ständigDer Plugin-Step hat failed zurückgegeben oder geworfen. Retries und Circuit Breaker gehören dem Walker
Ein Hook-Wert wird ignoriertDie Antwort hat die strikte Validierung nicht bestanden, kam zu spät an, oder der Circuit ist offen. Prüfen Sie den Fallback-Grund im Hook-Zustell-Log

Tier-2-Hook-Fehler

Schlagen Sie den festen Fallback-Grund im Hook-Zustell-Log nach:

GrundWas zu prüfen ist
blocked_ssrf / redirect_refusedDer Endpoint löst auf eine private/interne Adresse auf oder er leitet weiter. Beides wird verweigert — veröffentlichen Sie einen öffentlichen https-Endpoint, der direkt antwortet
timeoutDer Endpoint hat länger als 5 s gebraucht
signature_missing / signature_mismatchIhre Antwort ist unsigniert oder falsch signiert. Signieren Sie den kanonischen String der Response, spiegeln Sie die Request-Nonce zurück und verwenden Sie v1=<hex>
stale_responseDer signierte Zeitstempel der Antwort liegt außerhalb der Toleranz von 30 s — prüfen Sie den Uhrenversatz
response_too_largeDie Antwort hat 64 KiB überschritten
invalid_json / invalid_responseDer Body hat nicht exakt die Form für diese Hook-Art. Zusätzliche Keys, falsche Typen und leere Strings werden abgelehnt
capability_deniedDer Operator hat dieser App diese Hook-Art nicht gewährt
circuit_openFünf aufeinanderfolgende Fehlschläge haben den Breaker ausgelöst; nach 60 s versucht er einen Probeaufruf
app_disabled / app_revokedOperator-Aktion — der Widerruf ist terminal
secret_unavailableDas versiegelte Secret konnte nicht geöffnet werden. Meist ein geändertes INSTANCE_SECRET — rotieren Sie das Secret der App

Tier-3-Job-Fehler

SymptomUrsache
Es erscheinen keine Plugin-JobsHeute erwartet: worker:enqueue ist reserviert und es wird kein Host-Enqueue-Adapter ausgeliefert
worker_timeoutDer Job hat seine host-geklemmte Wall Clock überschritten; die gesamte Prozessgruppe wurde getötet
worker_failed nach mehreren VersuchenDer Job hat sein geklemmtes Versuchsbudget (≤ 5) aufgebraucht und endete als failed
Jobs gehen von selbst zurück auf queuedLease Reclaim nach einem Absturz oder Neustart des Workers
Ein Job kann kein Credential lesenKorrekt und beabsichtigt. Die Job-Umgebung ist von jedem Ambient-Credential bereinigt; vermitteln Sie es über den Host