{"record":{"id":"8224b9dc1731fcd6","repo":"windmill-labs/windmill","slug":"unknown-portal-target-type-target-null-n","errorCode":null,"errorMessage":"Unknown portal target type: ${target === null ? 'null' : typeof target}. Allowed types: string (CSS selector) or HTMLElement.","messagePattern":"Unknown portal target type: (.+?)\\. Allowed types: string \\(CSS selector\\) or HTMLElement\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/Portal.svelte","lineNumber":21,"sourceCode":"\n\texport function portal(el, options) {\n\t\tlet { target, name } = options\n\t\tlet targetEl\n\t\tasync function update(newTarget) {\n\t\t\ttarget = newTarget\n\t\t\tif (typeof target === 'string') {\n\t\t\t\ttargetEl = document.querySelector(target)\n\t\t\t\tif (targetEl === null) {\n\t\t\t\t\tawait tick()\n\t\t\t\t\ttargetEl = document.querySelector(target)\n\t\t\t\t}\n\t\t\t\tif (targetEl === null) {\n\t\t\t\t\tthrow new Error(`No element found matching css selector: \"${target}\"`)\n\t\t\t\t}\n\t\t\t} else if (target instanceof HTMLElement) {\n\t\t\t\ttargetEl = target\n\t\t\t} else {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`Unknown portal target type: ${\n\t\t\t\t\t\ttarget === null ? 'null' : typeof target\n\t\t\t\t\t}. Allowed types: string (CSS selector) or HTMLElement.`\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (!el.classList.contains('windmill-app')) {\n\t\t\t\tel.classList.add('windmill-app')\n\t\t\t}\n\t\t\tif (name && !el.classList.contains(name)) {\n\t\t\t\tel.classList.add(name)\n\t\t\t}\n\t\t\ttargetEl.appendChild(el)\n\t\t\tel.hidden = false\n\t\t}\n\n\t\tfunction destroy() {\n\t\t\tif (el.parentNode) {\n\t\t\t\tel.parentNode.removeChild(el)","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/Portal.svelte#L3-L39","documentation":"Portal's target prop must be either a CSS selector string or an HTMLElement. update() throws a TypeError when target is anything else (null, undefined, number, object), because there is no valid DOM node to portal into.","triggerScenarios":"<Portal target={undefined}> because a variable is not yet assigned; target={null} from a failed lookup; passing a non-DOM object (e.g. a Svelte store value or config object) as target.","commonSituations":"Binding target to data that loads asynchronously so it is undefined at first render; refactoring from string selectors to elements (or vice versa) and leaving a wrong type; a parent component passing an optional prop straight through.","solutions":["Only render <Portal> once the target variable is a string or HTMLElement (guard with {#if})","Pass an HTMLElement via bind:this instead of a nullable lookup result","Provide a default selector string, e.g. 'body'","Fix the type of the value being passed — it must be string | HTMLElement"],"exampleFix":"// before\n<Portal target={maybeEl}>...</Portal>\n// after\n{#if typeof maybeTarget === 'string' || maybeTarget instanceof HTMLElement}\n  <Portal target={maybeTarget}>...</Portal>\n{/if}","handlingStrategy":"type-guard","validationCode":"const validTarget = typeof target === 'string' || target instanceof HTMLElement\nif (!validTarget) target = 'body' // safe default","typeGuard":"function isPortalTarget(t: unknown): t is string | HTMLElement {\n  return typeof t === 'string' || t instanceof HTMLElement\n}","tryCatchPattern":"try {\n  renderPortal(target)\n} catch (e) {\n  if (e instanceof TypeError && e.message.startsWith('Unknown portal target type')) {\n    console.warn('Bad portal target, defaulting to body', target)\n    renderPortal('body')\n  } else throw e\n}","preventionTips":["Guard async-loaded target values with {#if} before rendering <Portal>","Never pass nullable lookup results directly as target","Type the target prop explicitly as string | HTMLElement | undefined in wrappers"],"tags":["dom","svelte","portal","typeerror"],"backgroundTag":"invalid-prop-type","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}