{"record":{"id":"d2a813b5afb0a89d","repo":"eythaann/Seelen-UI","slug":"missing-widget-id-on-webview-label","errorCode":null,"errorMessage":"Missing widget id on webview label","messagePattern":"Missing widget id on webview label","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"libs/core/src/state/widget/mod.ts","lineNumber":419,"sourceCode":"\ntype ExtendedGlobalThis = typeof globalThis & {\n  __SLU_WIDGET?: IWidget;\n  __SLU_WIDGET_INSTANCE?: Widget;\n};\n\nexport const SeelenSettingsWidgetId: WidgetId = \"@seelen/settings\" as WidgetId;\nexport const SeelenPopupWidgetId: WidgetId = \"@seelen/dialog\" as WidgetId;\nexport const SeelenWegWidgetId: WidgetId = \"@seelen/weg\" as WidgetId;\nexport const SeelenToolbarWidgetId: WidgetId = \"@seelen/fancy-toolbar\" as WidgetId;\nexport const SeelenWindowManagerWidgetId: WidgetId = \"@seelen/window-manager\" as WidgetId;\nexport const SeelenWallWidgetId: WidgetId = \"@seelen/wallpaper-manager\" as WidgetId;\n\nfunction getDecodedWebviewLabel(): [WidgetId, string | undefined] {\n  const encondedLabel = getCurrentWebview().label;\n  const decodedLabel = new TextDecoder().decode(decodeBase64Url(encondedLabel));\n  const [id, query] = decodedLabel.split(\"?\");\n  if (!id) {\n    throw new Error(\"Missing widget id on webview label\");\n  }\n  return [id as WidgetId, query];\n}\n\nfunction getDefinitionDefaultValues(definition: WidgetConfigDefinition): Record<string, unknown> {\n  const config: Record<string, unknown> = {};\n\n  // Check if it's a group (has \"group\" property)\n  if (\"group\" in definition) {\n    // Recursively process all items in the group\n    for (const item of definition.group.items) {\n      Object.assign(config, getDefinitionDefaultValues(item));\n    }\n  } else {\n    // It's a setting item, extract key and defaultValue\n    const item = definition as WidgetSettingItem;\n    if (\"key\" in item && \"defaultValue\" in item) {\n      config[item.key] = item.defaultValue;","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/eythaann/Seelen-UI/blob/dee4aaa94066c5d0888ab25554864862fc47be15/libs/core/src/state/widget/mod.ts#L401-L437","documentation":"Seelen UI encodes each widget webview's identity as a base64url label of the form '<widgetId>?<query>'. getDecodedWebviewLabel() decodes the current webview's label and splits it; if the decoded label has no part before the '?', there is no widget id, meaning the label was not produced by the widget spawn machinery, so the library cannot determine which widget is running.","triggerScenarios":"Accessing [id, query] or the query getter on a webview whose label is not a base64url-encoded 'id?query' string — a webview created manually in Tauri, a label that decodes to an empty string, or a Seelen UI/lib version mismatch where label encoding changed; tests mocking getCurrentWebview() with a plain label like 'main'.","commonSituations":"Running widget code in a webview registered outside the Seelen UI widget factory; hand-crafting webview labels in custom tooling; upgrading Seelen UI or the lib so the label format differs; test mocks using unencoded labels.","solutions":["Load the widget through Seelen UI's standard widget creation path so its label is the encoded id?query form.","If mocking in tests, set the label to the correct base64url encoding of '<widgetId>'.","Verify the current webview's label decodes to a non-empty widget id before use.","Align @seelen-ui/lib and Seelen UI versions to avoid label-format mismatches."],"exampleFix":"// before (test mock): getCurrentWebview: () => ({ label: 'main' })\n// after: getCurrentWebview: () => ({ label: toBase64Url('my-widget@example') }) // decodes to a real widget id","handlingStrategy":"validation","validationCode":"const label = getCurrentWebview().label; const decoded = new TextDecoder().decode(decodeBase64Url(label)); if (!decoded.split('?')[0]) throw new Error('webview label has no widget id');","typeGuard":"function hasWidgetIdLabel(label: string): boolean { try { return Boolean(new TextDecoder().decode(decodeBase64Url(label)).split('?')[0]); } catch { return false; } }","tryCatchPattern":"let id: WidgetId | undefined; try { [id] = getDecodedWebviewLabel(); } catch (e) { if (e instanceof Error && e.message.includes('Missing widget id')) { id = undefined; } else { throw e; } }","preventionTips":["Create widget webviews only through Seelen UI's widget spawn path.","In tests, mock labels with properly base64url-encoded ids.","Assert the decoded label shape once at startup to fail fast with context.","Align lib and app versions to avoid label-format drift."],"tags":["label","encoding","webview"],"backgroundTag":"invalid-webview-label","analyzedSha":"dee4aaa94066c5d0888ab25554864862fc47be15","analyzedAt":"2026-09-03T10:20:37.842Z","contentChangedAt":"2026-09-03T10:20:37.842Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}