[{"data":1,"prerenderedAt":1072},["ShallowReactive",2],{"search-en":3,"content-en-developer\u002Fplugin-troubleshooting":4,"surround-en-\u002Fdeveloper\u002Fplugin-troubleshooting":1063},[],{"id":5,"title":6,"body":7,"description":1055,"extension":1056,"meta":1057,"navigation":1058,"path":1059,"seo":1060,"stem":1061,"__hash__":1062},"content_en\u002F3.developer\u002F48.plugin-troubleshooting.md","Plugin Troubleshooting",{"type":8,"value":9,"toc":1044},"minimark",[10,14,19,50,167,170,255,259,265,465,570,574,580,712,716,719,757,761,764,828,832,835,972,976],[11,12,13],"p",{},"Plugin failures are deliberately loud and fail closed. Almost every one falls into four families: the manifest is invalid, composition is invalid or stale, authorization was denied, or a contribution hit its declared safe fallback.",[15,16,18],"h2",{"id":17},"manifest-errors","Manifest errors",[11,20,21,25,26,29,30,33,34,37,38,41,42,45,46,49],{},[22,23,24],"code",{},"definePlugin"," and ",[22,27,28],{},"parsePluginManifest"," throw ",[22,31,32],{},"PluginManifestError"," with one issue per problem: ",[22,35,36],{},"{ code, path, message }",", where ",[22,39,40],{},"path"," is a JSON pointer-ish string like ",[22,43,44],{},"$.contributes.crons[0].timeoutMs",". ",[22,47,48],{},"validatePluginManifest"," returns the same issues without throwing.",[51,52,53,66],"table",{},[54,55,56],"thead",{},[57,58,59,63],"tr",{},[60,61,62],"th",{},"Issue code",[60,64,65],{},"Typical cause",[67,68,69,92,102,127,137,147,157],"tbody",{},[57,70,71,77],{},[72,73,74],"td",{},[22,75,76],{},"missing",[72,78,79,80,83,84,87,88,91],{},"A required field is absent — most often ",[22,81,82],{},"$.flag"," for a plugin that contributes, uses storage, or requests ",[22,85,86],{},"llm:invoke","; or ",[22,89,90],{},"$.capabilities"," missing the capability a declared bucket requires",[57,93,94,99],{},[72,95,96],{},[22,97,98],{},"invalid_type",[72,100,101],{},"Wrong JavaScript type, or an accessor property where data was required",[57,103,104,109],{},[72,105,106],{},[22,107,108],{},"invalid_format",[72,110,111,114,115,118,119,122,123,126],{},[22,112,113],{},"id"," is not lowercase kebab-case ≤ 64 chars, ",[22,116,117],{},"version"," is not semver, a capability is not ",[22,120,121],{},"domain:action",", an env var is not ",[22,124,125],{},"UPPER_SNAKE",", or an export path is not a safe relative package export",[57,128,129,134],{},[72,130,131],{},[22,132,133],{},"duplicate",[72,135,136],{},"A repeated capability or required env var",[57,138,139,144],{},[72,140,141],{},[22,142,143],{},"unknown_field",[72,145,146],{},"A field or contribution bucket the platform does not know",[57,148,149,154],{},[72,150,151],{},[22,152,153],{},"too_many_items",[72,155,156],{},"Over a ceiling: 64 capabilities, 64 env vars, 256 entries per bucket, 64 settings fields",[57,158,159,164],{},[72,160,161],{},[22,162,163],{},"accessor_not_allowed",[72,165,166],{},"A getter\u002Fsetter where the validator requires plain data — manifests are inspected as data and never invoked",[11,168,169],{},"Frequent first-time mistakes:",[171,172,173,193,208,221,234],"ul",{},[174,175,176,188,189,192],"li",{},[177,178,179,180,183,184,187],"strong",{},"\"must declare ",[22,181,182],{},"\u003Ccapability>"," when ",[22,185,186],{},"\u003Cnouns>"," are contributed\""," — add the capability constant to ",[22,190,191],{},"capabilities",".",[174,194,195,201,202,204,205,192],{},[177,196,197,198,200],{},"\"",[22,199,82],{}," must be a plain object when …\""," — every contribution bucket, both storage capabilities, and ",[22,203,86],{}," require an explicit ",[22,206,207],{},"flag",[174,209,210,216,217,220],{},[177,211,212,215],{},[22,213,214],{},"llmBudget"," rejected"," — ",[22,218,219],{},"dailyUsd"," must be > 0, ≤ 1 000 000, and expressible with at most six decimal places.",[174,222,223,216,226,229,230,233],{},[177,224,225],{},"Cron rejected",[22,227,228],{},"intervalMinutes"," must be 15 … 40 320 and ",[22,231,232],{},"timeoutMs"," 1 000 … 300 000.",[174,235,236,242,243,246,247,250,251,254],{},[177,237,238,239,197],{},"\"must be listed in ",[22,240,241],{},"$.flag.requiredEnvVars"," — a feedback webhook's ",[22,244,245],{},"signature.secretEnvVar"," must also appear in ",[22,248,249],{},"flag.requiredEnvVars",". Without the secret the route can only answer ",[22,252,253],{},"503",", and listing it makes the plugin un-enableable until an operator sets it instead.",[15,256,258],{"id":257},"codegen-errors","Codegen errors",[11,260,261,264],{},[22,262,263],{},"PluginCodegenError"," carries a code plus a details list.",[51,266,267,277],{},[54,268,269],{},[57,270,271,274],{},[60,272,273],{},"Code",[60,275,276],{},"Meaning and fix",[67,278,279,292,313,327,340,350,360,378,388,405,415,425,435,445,455],{},[57,280,281,286],{},[72,282,283],{},[22,284,285],{},"config_invalid",[72,287,288,291],{},[22,289,290],{},"plugins.config.ts"," is not a literal package-name list. It is parsed as data, never evaluated — keep it a plain array",[57,293,294,299],{},[72,295,296],{},[22,297,298],{},"dependency_missing",[72,300,301,309,310],{},[302,303,304,305,308],"em",{},"\"Bundled plugin ",[22,306,307],{},"\u003Cname>"," must be installed as a root dependency or optionalDependency.\""," Install it at the workspace root from the registry, then re-run ",[22,311,312],{},"add",[57,314,315,320],{},[72,316,317],{},[22,318,319],{},"dependency_provenance",[72,321,322,323,326],{},"Installed metadata, ",[22,324,325],{},"bun.lock"," integrity, or realpath containment did not match. Aliases and git\u002FURL\u002Ffile\u002Fworkspace sources fail closed by design",[57,328,329,334],{},[72,330,331],{},[22,332,333],{},"package_load_failed",[72,335,336,337,339],{},"The package's manifest entry could not be imported. Check that the default export is the ",[22,338,24],{}," manifest and that importing it has no side effects",[57,341,342,347],{},[72,343,344],{},[22,345,346],{},"conditional_manifest_export",[72,348,349],{},"The manifest export is condition-dependent, so Bun, Convex, Nuxt SSR, and the browser build could resolve different manifests. Use one condition-independent root export",[57,351,352,357],{},[72,353,354],{},[22,355,356],{},"invalid_manifest",[72,358,359],{},"The loaded manifest failed validation — see the manifest table above",[57,361,362,371],{},[72,363,364,367,368],{},[22,365,366],{},"component_export_invalid"," \u002F ",[22,369,370],{},"contribution_export_invalid",[72,372,373,374,377],{},"A declared ",[22,375,376],{},"exportPath"," is not an exact, existing, condition-independent package export",[57,379,380,385],{},[72,381,382],{},[22,383,384],{},"composition_invalid",[72,386,387],{},"Duplicate package names, duplicate manifest ids, or a contribution graph the host rejects (unknown or terminal agent-step anchor, duplicate kind, insertion cycle, unsafe lifecycle edge)",[57,389,390,395],{},[72,391,392],{},[22,393,394],{},"generated_files_stale",[72,396,397,400,401,404],{},[22,398,399],{},"--check"," found missing or out-of-date output. Run ",[22,402,403],{},"bun run plugins:codegen"," and commit the result with the config change",[57,406,407,412],{},[72,408,409],{},[22,410,411],{},"generated_path_unsafe",[72,413,414],{},"A generated target or a parent directory is a symlink. Output is written through an exclusive temp file and an atomic rename and refuses to follow links",[57,416,417,422],{},[72,418,419],{},[22,420,421],{},"direct_plugin_import",[72,423,424],{},"Core source imports a configured plugin package outside the generated composition files — including via a Node\u002FBun loader or a repository alias. Route the import through the generated registry",[57,426,427,432],{},[72,428,429],{},[22,430,431],{},"repository_inventory_invalid",[72,433,434],{},"The boundary scan could not build its bounded file inventory, or the repository exceeds the scan's file safety limit",[57,436,437,442],{},[72,438,439],{},[22,440,441],{},"repository_config_invalid",[72,443,444],{},"A repository alias configuration (tsconfig paths, bundler aliases) could not be read safely, or alias discovery exceeded its file limit",[57,446,447,452],{},[72,448,449],{},[22,450,451],{},"source_invalid",[72,453,454],{},"A source file could not be parsed while scanning for the import-boundary rule",[57,456,457,462],{},[72,458,459],{},[22,460,461],{},"workspace_not_found",[72,463,464],{},"The command was run outside the Owlat workspace",[466,467,470,487,526],"callout",{"title":468,"type":469},"Run the CLI from a prepared workspace","tip",[11,471,472,475,476,479,480,367,483,486],{},[22,473,474],{},"Cannot find module '@owlat\u002Fplugin-kit'"," when invoking the CLI or codegen from source means the contracts have not been built yet. Run ",[22,477,478],{},"bun run plugins:prepare"," once (the ",[22,481,482],{},"plugins:codegen",[22,484,485],{},"plugins:check"," scripts do it for you).",[11,488,489,490,493,494,497,498,501,502,505,506,509,510,513,514,517,518,521,522,525],{},"The same applies to running ",[22,491,492],{},"packages\u002Fplugin-codegen"," or ",[22,495,496],{},"packages\u002Fplugin-cli"," tests directly with ",[22,499,500],{},"vitest",". Those packages deliberately do ",[177,503,504],{},"not"," rebuild the contracts themselves: ",[22,507,508],{},"packages\u002Fplugin-kit\u002Fdist"," is a shared artifact rebuilt with ",[22,511,512],{},"tsup --clean",", so a package-local rebuild would wipe it underneath whatever else the run is compiling. Turbo owns that ordering instead (",[22,515,516],{},"test"," depends on ",[22,519,520],{},"@owlat\u002Fplugin-kit#build","), and ",[22,523,524],{},"bun run lint:build-graph"," fails if a package script starts rebuilding it again.",[11,527,528,529,532,533,536,537,367,540,543,544,546,547,550,551,554,555,558,559,562,563,566,567,192],{},"That guard also covers ",[22,530,531],{},"packages\u002Fplugin-kit"," itself — only its ",[22,534,535],{},"build"," and its publish-only ",[22,538,539],{},"prepack",[22,541,542],{},"postpack"," hooks may drive the ",[22,545,512],{},", so the package smoke packs with ",[22,548,549],{},"--ignore-scripts"," and asserts it left ",[22,552,553],{},"dist\u002F"," untouched — and the repository root, where ",[22,556,557],{},"plugins:prepare"," is the one sanctioned entry point: any other root script reaching into another workspace directory with ",[22,560,561],{},"--cwd"," fails the guard unless it is added to ",[22,564,565],{},"ROOT_CWD_ALLOWLIST"," in ",[22,568,569],{},"scripts\u002Fcheck-build-graph.ts",[15,571,573],{"id":572},"host-denials","Host denials",[11,575,576,579],{},[22,577,578],{},"PluginHostError"," is raised at the enforcement boundary. Its code says exactly which link in the chain failed.",[51,581,582,594],{},[54,583,584],{},[57,585,586,588,591],{},[60,587,273],{},[60,589,590],{},"Meaning",[60,592,593],{},"Fix",[67,595,596,609,622,635,651,667,686,699],{},[57,597,598,603,606],{},[72,599,600],{},[22,601,602],{},"capability_not_declared",[72,604,605],{},"The manifest never requested this capability",[72,607,608],{},"Add it to the manifest and redeploy — a grant cannot widen a manifest",[57,610,611,616,619],{},[72,612,613],{},[22,614,615],{},"capability_not_granted",[72,617,618],{},"Declared, but the operator has not granted it",[72,620,621],{},"Enable the plugin and approve its capabilities in Settings → Plugins",[57,623,624,629,632],{},[72,625,626],{},[22,627,628],{},"plugin_disabled",[72,630,631],{},"The feature flag is off",[72,633,634],{},"Enable the flag",[57,636,637,642,648],{},[72,638,639],{},[22,640,641],{},"required_environment_missing",[72,643,644,645,647],{},"A ",[22,646,249],{}," variable is absent",[72,649,650],{},"Set it in the deployment environment; enablement is blocked until every one is present",[57,652,653,661,664],{},[72,654,655,367,658],{},[22,656,657],{},"environment_check_failed",[22,659,660],{},"feature_check_failed",[72,662,663],{},"The host could not evaluate the environment or the flag",[72,665,666],{},"Infrastructure problem — the operation fails closed, which is intended",[57,668,669,680,683],{},[72,670,671,367,674,367,677],{},[22,672,673],{},"invalid_capability_grant",[22,675,676],{},"invalid_manifest_snapshot",[22,678,679],{},"invalid_contribution",[72,681,682],{},"Host configuration or composition is inconsistent",[72,684,685],{},"Re-run codegen; if it persists, the composition and the deployment have drifted",[57,687,688,693,696],{},[72,689,690],{},[22,691,692],{},"untrusted_output_rejected",[72,694,695],{},"A plugin returned a non-string on a text boundary, or the scrubber failed",[72,697,698],{},"Return a plain string from the module",[57,700,701,706,709],{},[72,702,703],{},[22,704,705],{},"invalid_untrusted_text_policy",[72,707,708],{},"A host adapter named an invalid policy",[72,710,711],{},"Host bug, not a plugin bug",[15,713,715],{"id":714},"my-contribution-isnt-running","\"My contribution isn't running\"",[11,717,718],{},"Work down this list — it is the same order the host checks:",[720,721,722,732,735,738,741,747,750],"ol",{},[174,723,724,725,727,728,731],{},"Is the package in ",[22,726,290],{}," and is the generated composition current (",[22,729,730],{},"bun run plugins:check",")?",[174,733,734],{},"Was the deployment rebuilt after the config change? Bundled composition is a build-time artifact.",[174,736,737],{},"Is the plugin's feature flag enabled?",[174,739,740],{},"Were its capabilities approved when it was enabled? Disabling clears the grant record.",[174,742,743,744,746],{},"Are all ",[22,745,249],{}," present in the deployment environment?",[174,748,749],{},"Does the manifest declare the capability the bucket requires?",[174,751,752,753,756],{},"For nav and settings entries: does the target section exist and is it feature-on? Does another entry already own the same ",[22,754,755],{},"href","? Dedup is by href, first-registered-wins, and core registers first.",[15,758,760],{"id":759},"the-contribution-ran-but-nothing-changed","\"The contribution ran but nothing changed\"",[11,762,763],{},"That is usually a safe fallback doing its job. Each bucket has a declared direction:",[51,765,766,776],{},[54,767,768],{},[57,769,770,773],{},[60,771,772],{},"Symptom",[60,774,775],{},"Likely cause",[67,777,778,789,800,808,820],{},[57,779,780,783],{},[72,781,782],{},"Replies keep going to human review",[72,784,785,786],{},"A plugin gate objected, timed out, threw, returned malformed output, or was denied. Gates fail ",[177,787,788],{},"closed",[57,790,791,794],{},[72,792,793],{},"Drafts look like the built-in ones",[72,795,796,797],{},"The plugin draft strategy was denied, timed out, failed, or produced oversized\u002Finjection-like output — one fallback to ",[22,798,799],{},"default",[57,801,802,805],{},[72,803,804],{},"An agent step vanished from the pipeline",[72,806,807],{},"Authorization was denied at the last moment. The walker skips the contribution and resumes the unchanged core continuation",[57,809,810,813],{},[72,811,812],{},"An automation step keeps retrying",[72,814,815,816,819],{},"The plugin step returned ",[22,817,818],{},"failed"," or threw. The walker owns retries and the circuit breaker",[57,821,822,825],{},[72,823,824],{},"A hook value is ignored",[72,826,827],{},"The response failed strict validation, arrived late, or the circuit is open. Check the hook delivery log's fallback reason",[15,829,831],{"id":830},"tier-2-hook-failures","Tier-2 hook failures",[11,833,834],{},"Look up the fixed fallback reason in the hook delivery log:",[51,836,837,847],{},[54,838,839],{},[57,840,841,844],{},[60,842,843],{},"Reason",[60,845,846],{},"What to check",[67,848,849,862,872,892,902,912,925,935,945,958],{},[57,850,851,859],{},[72,852,853,367,856],{},[22,854,855],{},"blocked_ssrf",[22,857,858],{},"redirect_refused",[72,860,861],{},"The endpoint resolves to a private\u002Finternal address, or it redirects. Both are refused — publish a public https endpoint that answers directly",[57,863,864,869],{},[72,865,866],{},[22,867,868],{},"timeout",[72,870,871],{},"The endpoint took longer than 5 s",[57,873,874,882],{},[72,875,876,367,879],{},[22,877,878],{},"signature_missing",[22,880,881],{},"signature_mismatch",[72,883,884,885,888,889],{},"Your response is unsigned or signed wrong. Sign the ",[177,886,887],{},"response"," canonical string, echo the request nonce, use ",[22,890,891],{},"v1=\u003Chex>",[57,893,894,899],{},[72,895,896],{},[22,897,898],{},"stale_response",[72,900,901],{},"The response's signed timestamp is outside the 30 s tolerance — check clock skew",[57,903,904,909],{},[72,905,906],{},[22,907,908],{},"response_too_large",[72,910,911],{},"The response exceeded 64 KiB",[57,913,914,922],{},[72,915,916,367,919],{},[22,917,918],{},"invalid_json",[22,920,921],{},"invalid_response",[72,923,924],{},"The body is not exactly the shape for that hook kind. Extra keys, wrong types, and empty strings are rejected",[57,926,927,932],{},[72,928,929],{},[22,930,931],{},"capability_denied",[72,933,934],{},"The operator did not grant this hook kind to this app",[57,936,937,942],{},[72,938,939],{},[22,940,941],{},"circuit_open",[72,943,944],{},"Five consecutive failures tripped the breaker; it retries one trial call after 60 s",[57,946,947,955],{},[72,948,949,367,952],{},[22,950,951],{},"app_disabled",[22,953,954],{},"app_revoked",[72,956,957],{},"Operator action — revoked is terminal",[57,959,960,965],{},[72,961,962],{},[22,963,964],{},"secret_unavailable",[72,966,967,968,971],{},"The sealed secret could not be opened. Usually a changed ",[22,969,970],{},"INSTANCE_SECRET"," — rotate the app's secret",[15,973,975],{"id":974},"tier-3-job-failures","Tier-3 job failures",[51,977,978,987],{},[54,979,980],{},[57,981,982,984],{},[60,983,772],{},[60,985,986],{},"Cause",[67,988,989,1001,1011,1024,1036],{},[57,990,991,994],{},[72,992,993],{},"No plugin jobs appear",[72,995,996,997,1000],{},"Expected today: ",[22,998,999],{},"worker:enqueue"," is reserved and no host enqueue adapter is shipped",[57,1002,1003,1008],{},[72,1004,1005],{},[22,1006,1007],{},"worker_timeout",[72,1009,1010],{},"The job exceeded its host-clamped wall clock; the whole process group was killed",[57,1012,1013,1019],{},[72,1014,1015,1018],{},[22,1016,1017],{},"worker_failed"," after several attempts",[72,1020,1021,1022],{},"The job exhausted its clamped attempt budget (≤ 5) and terminated as ",[22,1023,818],{},[57,1025,1026,1033],{},[72,1027,1028,1029,1032],{},"Jobs go back to ",[22,1030,1031],{},"queued"," on their own",[72,1034,1035],{},"Lease reclaim after a worker crash or restart",[57,1037,1038,1041],{},[72,1039,1040],{},"A job cannot read a credential",[72,1042,1043],{},"Correct and intentional. The job environment is stripped of every ambient credential; mediate it through the host",{"title":1045,"searchDepth":1046,"depth":1046,"links":1047},"",2,[1048,1049,1050,1051,1052,1053,1054],{"id":17,"depth":1046,"text":18},{"id":257,"depth":1046,"text":258},{"id":572,"depth":1046,"text":573},{"id":714,"depth":1046,"text":715},{"id":759,"depth":1046,"text":760},{"id":830,"depth":1046,"text":831},{"id":974,"depth":1046,"text":975},"Manifest, codegen, host, and runtime failures — what each one means and how to fix it.","md",{},true,"\u002Fdeveloper\u002Fplugin-troubleshooting",{"title":6,"description":1055},"3.developer\u002F48.plugin-troubleshooting","w_XUDi-TnPVYGx-u8dAcFtdw2NRzIqz1ctWgc62SBj8",[1064,1068],{"title":1065,"path":1066,"stem":1067,"children":-1},"Sandboxed Plugin Jobs","\u002Fdeveloper\u002Fplugin-sandboxed-jobs","3.developer\u002F47.plugin-sandboxed-jobs",{"title":1069,"path":1070,"stem":1071,"children":-1},"Authoring a Send Provider","\u002Fdeveloper\u002Fplugin-send-providers","3.developer\u002F49.plugin-send-providers",1786915092938]