Debugging Wippy FE
Use these checks to isolate common Wippy frontend failures before changing application code.
Blank screen on load
1. Check the Console first:
Failed to resolve module specifier 'vue'— the page externalized a specifier that its active import map does not provide. In hosted mode inspect the import map actually served by the target Web Host release; in host-less mode inspect the map inapp.html. Compare every Rollup external against that exact map instead of assuming a canonical package list or merge precedence.Proxy globals not found(or your@wippy-fe/proxyimports come back undefined) —proxy.js/dev-proxy.jsdid not load before your app script ran, so the runtime never installed its internal globals. Check thatdev-proxy.jsis referenced withdata-role="@wippy/scripts"inapp.html.- Silent hang (no errors, no app) — in host-less mode, the dev overlay may be waiting for you to click Accept. Confirm that its FAB (floating button) appeared. If it did not,
proxy.js/dev-proxy.jsfailed to load or install its globals; follow theProxy globals not foundcheck above.
Hosted iframe pages and host-less pages receive config synchronously before the
proxy boots. Web Fragment pages use the fragment adapter's
GetConfig/SetConfig handshake, as does the host-level manual
iframe.html?waitForCustomConfig embedding.
2. Check the Network tab:
- Confirm
dev-proxy.js(host-less) orproxy.js(hosted) loaded with status 200. - If 404: the
srcin your<script data-role="@wippy/scripts">tag points to the wrong URL.
3. Check the runtime installed its globals (internal diagnostic):
// Internal globals — app code never reads these; this is only a console smoke test
// that the proxy runtime mounted. App/WC code uses `import { ... } from '@wippy-fe/proxy'`.
window.$W // should be an object, not undefined
window.__WIPPY_APP_API__ // the resolved proxy instance — present once the runtime installed
The @wippy-fe/proxy getters read these globals (window.__WIPPY_APP_API__ is the live host instance); that is separate from how the module URL resolves. If the globals exist but imports fail, inspect the active import map and the network response for the exact @wippy-fe/proxy specifier. Fix the map or externalization decision in the environment that serves the page; do not infer hosted behavior from a successful host-less boot.
Web component never appears
1. Verify the three gates:
Run from your backend:
curl /api/public/components/list?auto_register=true
Your component's tag_name must appear in the response. If not:
announced: truemissing in_index.yaml→ add itauto_register: truemissing → add it- Component is not registered with
wippy/views→ check your module deps
2. Check the Console:
customElements.get('your-tag-name') // undefined means the element was not registered
3. Check the Network tab:
- Filter for your component's
index.jsURL - The URL should contain
?declare-tag=your-tag-name— this is how the element registers itself - If the URL has no
?declare-tag=query:define(import.meta.url, MyElement)was not retained in the entry chunk. Setbuild.rollupOptions.preserveEntrySignaturesto'strict';falsecan move the registration side effect out of the entry. See Build System
API calls failing / 401
1. In host-less mode:
- The
dev-tokenstub in the proxy config is not a real credential and normally must be replaced before calling an authenticated backend - Open the dev overlay → find the
auth.tokenfield in the JSON config → paste a real bearer token - Confirm
APP_API_URLin the overlay config points to the running backend (not localhost if your backend is elsewhere)
2. In hosted mode:
- Use the proxy
apiclient. For eligible same-origin 401 responses it single-flights and callshost.handleError('auth-expired', error)automatically. - If all API calls 401, check the Host config and session-token injection. Call
host.handleErrormanually only for a request path that deliberately bypasses the standard proxy client and therefore cannot receive its automatic handling.
Theme looks wrong
1. In host-less mode:
The dev overlay starts with themeConfig, primevue, markdown, and iframe
injection disabled by default. The base theme, PrimeVue, Markdown, and
scrollbar sheets are therefore absent until you enable them; customCss and
customVariables remain enabled by default.
Open the dev overlay FAB → toggle the CSS injections you need → check "Auto-accept on reload".
2. Compare the complete effective chain:
A non-empty token is not sufficient. Use distinct values so a stock-palette reset or accidental family alias is obvious:
css_variables:
"--p-primary": "#dc2626"
"--p-secondary": "#7c3aed"
"--p-accent": "#0d9488"
"--p-danger": "#be123c"
"--p-success": "#15803d"
"--p-warn": "#c2410c"
"--p-info": "#0369a1"
"--p-help": "#9333ea"
"--theme-diagnostic-sentinel": "#123456"
Then compare, in this order:
- Effective configured map: inspect
config.theming.global.cssVariablesand confirm the base plus the active@light/@darkreplacements. - Page root: read the exact token with
getComputedStyle(document.documentElement).getPropertyValue(name).trim(). - WC host: read the same token from
getComputedStyle(customElement). - WC inner root: read it from
getComputedStyle(customElement.shadowRoot.querySelector('[data-wippy-theme-root]')). - Rendered semantic color: put
background-color: var(--p-<family>-color)on a probe and compare its computedbackgroundColor; this resolvescolor-mix()in the browser.
Repeat in Auto-light, Auto-dark, forced Light, and forced Dark. For each configured family verify its base, all 50–950 shades, color, contrast-color, hover-color, and active-color; also verify a direct shade/alias override, a surface token, and the sentinel. Page, host, and inner values must agree.
Interpret the first divergence: wrong effective map means configuration/merge; wrong page root means variable compilation/injection; correct page but wrong WC host means host propagation; correct WC host but wrong inner root means the forced-theme bridge or local defaults; equal tokens but wrong rendered color means the consuming selector or semantic alias is wrong.
3. Web component specific:
- If the platform defaults are absent, check that
hostCssKeysincludes'themeConfigUrl'. - If the host is correct but the inner root resets to stock values, verify a current
@wippy-fe/webcomponent-core; do not copy a palette into component CSS. - If PrimeVue components render unstyled, add
'primeVueCssUrl'tohostCssKeys.
See Theming: Micro Frontend Apps or Theming: Web Components for the full injection pipeline.
Host URL bar doesn't update
Portable micro frontend apps must use the createAppRouter() factory from @wippy-fe/router. The package owns both directions of host synchronization; application code must not reproduce router.afterEach and @history wiring.
Check:
import { createAppRouter } from '@wippy-fe/router'
import { config } from '@wippy-fe/proxy'
import { routes } from './routes'
const router = createAppRouter(routes, {
initialPath: config.context?.route ?? '/',
})
If the host URL still does not update, confirm the current @wippy-fe/router family is installed coherently and that no local wrapper replaces the factory. In host-less mode, the dev overlay Monitor tab shows the route the package reports.
Attention context is missing or wrong
1. Check the public capability before inspecting internals:
import { attention } from '@wippy-fe/proxy'
console.log({
enabled: attention.enabled,
messageContext: attention.supports('message-context'),
agentActions: attention.supports('agent-actions'),
visualCapture: attention.supports('visual-capture'),
})
For missing automatic attachments, check the Session's attention_context.enabled
and the facade message-context capability. For missing interactive UI, check its
separate permission and provider. Bounded observation and authorized explicit
reads remain active with these controls off. Verify the Host selected by
fe_facade_url, use public inspection methods, and do not send private relay
messages or call coordinator internals from package code.
2. If a target is absent or vague:
- Confirm the pointer or focus event is real trusted browser input; synthetic events are intentionally ignored.
- Inspect the control’s native role, accessible name, visible label, and focus behavior.
- Look for
data-wippy-attention="exclude"on an ancestor. Aredactancestor retains geometry but removes descendant text. - Check
privacy.text;noneintentionally removes text summaries. - Read
capture.completeandomissions.child-timeout,capability-unavailable,stale-mount,navigation,redacted, and budget omissions explain partial paths without breaking the page.
3. If a nested or boundary target is wrong:
Verify that every boundary uses the same compatible Web Host/proxy family and
that mount generations stay stable while visible. At an edge-to-edge boundary,
the default 20 CSS-pixel radius and 5-pixel step should query both children. A
Web Fragment result should combine physical-host geometry with
fragment-realm runtime provenance.
4. If an agent overlay does not appear or immediately closes:
First check that agent actions are available at each layer:
- Host configuration. The facade
attentionrequirement must set"enabled": trueand"agentActions": {"enabled": true}, plus"visualCapture": {"enabled": true}for image capture. In the browser,attention.supports('agent-actions')andattention.supports('visual-capture')report the result. - Session.
GET /api/v1/sessions/capabilitiesmust reportattention.contextandattention.browser_operationsof at least 1. A404means the Session release has no capability descriptor, and the Host then sends no tab binding, so agent tools cannot reach the tab. - Agent. The agent must include the
wippy.agent.traits:attentiontrait, which providesui_action_highlight,ui_action_confirm,ui_action_selectandui_action_capture_visual.
For image capture, also check that the application's upload type accepts
image/png, and image/webp when that format is requested.
Then confirm an active authenticated WebSocket connection, the current session
and Host instance, and a non-expired target reference. A navigation, remount,
changed Host instance, timeout, or disconnect correctly returns a terminal
stale, expired, or disconnected result. Reconnect does not revive the old
request; the agent must issue a fresh action. See terminal
statuses for every result.
See Attention Context for Micro Frontends and Web Host Attention Context.
Works locally, breaks when hosted
1. Check relative asset resolution for the selected engine:
For iframe delivery, inspect:
document.baseURI // should be <url>/<base_path>/ from your registry entry
If it is wrong, the <base> tag was not injected correctly. Check that
base_path in _index.yaml matches the actual directory structure of the
built output.
Web Fragment delivery deliberately does not inject a <base> element. Inspect
the reflected head and body instead: relative href="./…" and src="./…"
attributes should be rewritten to the fragment gateway's asset URLs.
2. Check proxy globals (internal diagnostic):
window.__WIPPY_PROXY_CONFIG__ // internal — must exist in iframe-hosted mode
Undefined means the proxy was not injected before your app ran. App code never reads this directly; see Proxy & Isolation § Internals.
3. Confirm base: '' in vite.config.ts:
Without base: '', Vite emits absolute asset paths. The app loads fine on your local dev server (which serves from /) but 404s when served from a CDN subdirectory.
4. Import map mismatch:
Re-fetch <version-tag>/import-map.json from the Web Host release pinned by
fe_facade_url. Replace the complete imports object in host-less app.html
and regenerate Vite externals from all of its keys. Do not remove the host-less
map or patch individual entries. Bundle a newly imported exact specifier only
when it is absent from the fetched map.
Using the logger as a debugging tool
logger.debug() and logger.info() output appears in the browser Console during development — not just in production transports. Use it to trace the boot sequence:
import { logger, config, host, api } from '@wippy-fe/proxy'
export function createMainApp() {
logger.debug('App bootstrap started')
logger.debug('Host services resolved', { hasConfig: !!config })
// ... use config, host, api directly
}
logger.captureException(error) also logs to Console in dev mode and is caught by the host's error capture system in production.