Skip to content

Troubleshooting

Jim Daley edited this page May 1, 2026 · 3 revisions

Troubleshooting

Start with the runtime phase where the symptom appears: discovery, compatibility, entitlement, registry resolution, lifecycle, or UI surface rendering.

Triage Flow

flowchart TD
    Symptom["Observed failure"] --> Discover{"Manifest discovered?"}
    Discover -- no --> ManifestFix["Check bundle path and JSON schema"]
    Discover -- yes --> Compatible{"Compatibility report clean?"}
    Compatible -- no --> CompatFix["Fix schema, platform, version, or capability"]
    Compatible -- yes --> Unlocked{"Entitlement unlocked?"}
    Unlocked -- no --> EntFix["Check iapProductID and provider state"]
    Unlocked -- yes --> Factory{"Registry factory found?"}
    Factory -- no --> RegFix["Register matching entryPoint"]
    Factory -- yes --> Lifecycle{"start(context) succeeds?"}
    Lifecycle -- no --> StartFix["Inspect module error logs"]
    Lifecycle -- yes --> UI{"UI visible?"}
    UI -- no --> UIFix["Check active UI module, viewID, slot, and registry"]
    UI -- yes --> Done["Runtime path healthy"]
Loading

Common Symptoms

Symptom Likely Cause Fix
No modules discovered Manifest files are not bundled under ForsettiManifests. Check target membership and resource path.
validationFailed Manifest JSON is malformed or missing required fields. Validate JSON and compare with the schema page.
duplicateModuleID Two manifests share the same moduleID. Make module IDs globally unique.
incompatible(report:) Platform/version/capability check failed. Inspect compatibility issues and fix the manifest or policy.
moduleLocked Entitlement provider returned locked. Verify iapProductID, StoreKit state, or static unlock IDs.
moduleIdentityMismatch Factory returned a module whose descriptor or manifest does not match the discovered manifest. Align descriptor, bundled manifest, and registry entry point.
missingCapability Module contributed UI or resolved a service without the required capability. Add the required capability to the manifest or remove the contribution/service use.
notUIModule Manifest says ui or app, but factory returned a plain ForsettiModule. Return a ForsettiUIModule or ForsettiAppModule.
Active UI module not visible Activation did not succeed or injected view is not registered. Check activeUIModuleID, activation errors, and viewID registration.
Toolbar route fails Pointer/route ID missing or destination/slot unsupported. Check active OverlaySchema and host catalogs.
Module messages not received Target payload does not match subscriber module ID. Use sendModuleMessage and subscribe with the target ID.

Manifest Debug Checklist

flowchart LR
    Path["Resource path"] --> Fields["Required fields"]
    Fields --> Types["moduleType and platforms"]
    Types --> Version["Forsetti version range"]
    Version --> Caps["capabilitiesRequested"]
    Caps --> Entry["entryPoint"]
Loading

Required manifest root keys:

  • schemaVersion
  • moduleID
  • displayName
  • moduleVersion
  • moduleType
  • supportedPlatforms
  • minForsettiVersion
  • capabilitiesRequested
  • entryPoint

Logs to Check

Log Source Useful For
ConsoleForsettiLogger in debug builds Activation, deactivation, and module lifecycle messages.
ForsettiHostController.errorMessage User-visible controller failures.
ForsettiHostOverlayRouter.lastOutcome Pointer and route resolution failures.
Compatibility report Exact reason activation cannot proceed.
Platform logger Production-capable runtime diagnostics where OSLog is available.

Recovery Pattern

  1. Reproduce with the smallest manifest and module set.
  2. Confirm the manifest loads.
  3. Confirm compatibility is clean.
  4. Confirm entitlement unlock state.
  5. Confirm the registry entry point.
  6. Confirm module lifecycle behavior.
  7. Confirm UI contribution rendering.
  8. Add a focused regression test.

Clone this wiki locally