-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
James Daley edited this page Jun 18, 2026
·
3 revisions
Start with the runtime phase where the symptom appears: discovery, registration, compatibility, entitlement, registry resolution, lifecycle, or UI surface rendering.
flowchart TD
Symptom["Observed failure"] --> Discover{"Manifest discovered?"}
Discover -- no --> ManifestFix["Check bundle path and JSON schema"]
Discover -- yes --> Registered{"Registration record current?"}
Registered -- no --> RegistrationFix["Refresh discovery and inspect registration store"]
Registered -- yes --> Compatible{"Compatibility report clean?"}
Compatible -- no --> CompatFix["Fix schema, manifest template, 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 --> RuntimeReq{"Runtime requirements satisfied?"}
RuntimeReq -- no --> ReqFix["Check capabilities, providers, roles, and UI declarations"]
RuntimeReq -- 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"]
| 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, missing required fields, or declares an unsupported schema/template combination. | Validate JSON and compare with the schema page. |
duplicateModuleID |
Two manifests share the same moduleID. |
Make module IDs globally unique. |
registrationMissing |
Activation ran without a persisted registration record for the manifest. | Run discovery through boot or discoverModules before activation and verify the configured ModuleRegistrationStore. |
registrationMismatch |
Stored registration hash or identity fields no longer match the current manifest. | Rediscover manifests and inspect whether manifest identity changed unexpectedly. |
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, manifest property, and registry entry point. |
missingCapability |
Module contributed UI without the required capability. | Add the required capability to the manifest or remove the contribution. |
unsatisfiedRuntimeRequirement |
Required provider, default role, data isolation mode, or UI declaration is missing. | Check runtimeRequirements, host services, discovered default-role modules, and UI contribution IDs. |
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. |
| Theme mask does not appear | Default ModuleManager sanitizes themeMask before surface publication. |
Implement host-owned theming or custom runtime behavior intentionally. |
| Toolbar route fails | Pointer/route ID missing, undeclared, or destination/slot unsupported. | Check runtimeRequirements.ui, active OverlaySchema, and host catalogs. |
| Module messages not received | Target payload does not match subscriber module ID or guard denied the message. | Use sendMessage(to:type:payload:) and subscribe with the target module ID. |
flowchart LR
Path["Resource path"] --> Fields["Required root fields"]
Fields --> Template["schema/template pairing"]
Template --> Types["moduleType and platforms"]
Types --> Version["Forsetti version range"]
Version --> Caps["capabilitiesRequested"]
Caps --> Runtime["runtimeRequirements"]
Runtime --> Entry["entryPoint"]
Required manifest root keys:
schemaVersionmoduleIDdisplayNamemoduleVersionmoduleTypesupportedPlatformsminForsettiVersioncapabilitiesRequestedentryPoint
Current modules should also include:
manifestTemplateVersion-
defaultModuleRolewhen the module provides a default role runtimeRequirements
| Requirement Area | What to Check |
|---|---|
| I/O | Every runtimeRequirements.io.kind has the matching capability in capabilitiesRequested. |
| Required providers | Host ForsettiServiceContainer or discovered default-role modules provide required services. |
| Data isolation |
framework_mediated_shared has a shared_database provider. |
| Default roles | Role is valid for moduleType and service roles request the matching capability. |
| UI declarations | Every toolbar item, view ID, slot ID, route ID, pointer ID, and theme ID is listed under runtimeRequirements.ui. |
| Log Source | Useful For |
|---|---|
ConsoleForsettiLogger in debug builds |
Activation, deactivation, denied service resolution, 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. |
- Reproduce with the smallest manifest and module set.
- Confirm the manifest loads.
- Confirm the registration record exists and matches.
- Confirm compatibility is clean.
- Confirm entitlement unlock state.
- Confirm the registry entry point.
- Confirm runtime requirements and provider availability.
- Confirm module lifecycle behavior.
- Confirm UI contribution rendering.
- Add a focused regression test.