{"record":{"id":"e890529dad4f2e5b","repo":"bigskysoftware/htmx","slug":"invalid-re-target-target-e89052","errorCode":null,"errorMessage":"Invalid re-target ${target}","messagePattern":"Invalid re-target (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"www/static/src/htmx.js","lineNumber":4795,"sourceCode":"        window.document.title = title\n      }\n    }\n  }\n\n  /**\n   * Resove the Retarget selector and throw if not found\n   * @param {Element} elt\n   * @param {String} target\n   * @returns {Element}\n   */\n  function resolveRetarget(elt, target) {\n    if (target === 'this') {\n      return elt\n    }\n    const resolvedTarget = asElement(querySelectorExt(elt, target))\n    if (resolvedTarget == null) {\n      triggerErrorEvent(elt, 'htmx:targetError', { target })\n      throw new Error(`Invalid re-target ${target}`)\n    }\n    return resolvedTarget\n  }\n\n  /**\n   * @param {Element} elt\n   * @param {HtmxResponseInfo} responseInfo\n   */\n  function handleAjaxResponse(elt, responseInfo) {\n    const xhr = responseInfo.xhr\n    let target = responseInfo.target\n    const etc = responseInfo.etc\n    const responseInfoSelect = responseInfo.select\n\n    if (!triggerEvent(elt, 'htmx:beforeOnLoad', responseInfo)) return\n\n    if (hasHeader(xhr, /HX-Trigger:/i)) {\n      handleTriggerHeader(xhr, 'HX-Trigger', elt)","sourceCodeStart":4777,"sourceCodeEnd":4813,"githubUrl":"https://github.com/bigskysoftware/htmx/blob/ad56dff71e55d9c717447437b4c942a64575d4b2/www/static/src/htmx.js#L4777-L4813","documentation":"htmx retargets the swap destination via either the HX-Retarget response header or a target field on a responseHandling config entry matched by HTTP status code. resolveRetarget resolves that selector with querySelectorExt (which supports htmx's extended syntax: 'closest ', 'next ', 'previous ', 'find ', plus standard CSS), and if no element matches it fires the htmx:targetError event and throws, because htmx cannot decide where to place the response body. The throw is intentional and fatal for that request — the swap is aborted.","triggerScenarios":"Server returns an HX-Retarget response header whose CSS/extended selector matches zero elements; OR htmx.config.responseHandling contains an entry (e.g. {code:'422', target:'#form-errors'}) whose target selector is absent in the DOM when the XHR resolves. Reached via handleAjaxResponse at www/static/src/htmx.js:4854 (responseHandling.target) and www/static/src/htmx.js:4863 (HX-Retarget header). The special value 'this' short-circuits and returns elt, so it never throws.","commonSituations":"Typo or stale id/class in the HX-Retarget header sent by the backend; target element lives in a fragment that is conditionally rendered and is absent on the current code path; the element existed when the request was issued but was removed by a concurrent swap/removal before the response arrived; an extended selector like 'closest div' or 'next .item' is evaluated relative to elt which has no matching ancestor/sibling; selector targets an element inside a shadow root or different document. NOTE: www/static/src/htmx.js is a vendored/published copy that is byte-identical to src/htmx.js — a fix made in src/ will NOT propagate here until the static asset is rebuilt/copied; editing only this file risks drift.","solutions":["Open DevTools -> Network, inspect the failing XHR's Response Headers, read the exact HX-Retarget value, then confirm an element matching it exists in the DOM at response time.","Add a global listener to capture the offending selector at runtime: document.body.addEventListener('htmx:targetError', e => console.error('bad retarget:', e.detail.target, e.target)).","Fix the mismatch: correct the typo in the backend header or in htmx.config.responseHandling, or change the selector to one guaranteed present.","If the target is rendered conditionally, ensure it is in the DOM before the request fires (render a hidden placeholder), or have the server omit HX-Retarget when the element would be absent.","If you must change htmx itself, edit src/htmx.js (the source of truth) and rebuild/re-copy into www/static/src/ so the vendored copy does not drift — do not patch www/static/src/htmx.js in isolation."],"exampleFix":"// before — server sends HX-Retarget: #user-toast but #user-toast is absent -> throws\n\n// after — make the element always present, then retarget safely:\n<div id=\"user-toast\" hidden></div>\n<button hx-post=\"/save\" hx-target=\"#user-toast\">Save</button>\n\n// or recover from the throw via the event instead:\ndocument.body.addEventListener('htmx:targetError', (e) => {\n  console.warn('retarget missed, falling back:', e.detail.target)\n})","handlingStrategy":"validation","validationCode":"// Run before issuing an htmx request whose server will send HX-Retarget,\n// to confirm the selector already resolves against the DOM.\nfunction retargetSelectorExists(rootEl, selector) {\n  if (selector === 'this') return true // resolveRetarget short-circuits on 'this'\n  if (!selector || typeof selector !== 'string') return false\n  return document.querySelector(selector) != null\n}\n\nconst btn = document.querySelector('#save-btn')\nconst sel = '#user-toast'\nif (!retargetSelectorExists(btn, sel)) {\n  console.warn('HX-Retarget target missing; skipping request')\n} else {\n  htmx.trigger(btn, 'submit')\n}","typeGuard":"function isResolvableRetarget(elt, selector) {\n  if (typeof selector !== 'string' || selector.length === 0) return false\n  if (selector === 'this') return true\n  const resolved = elt instanceof Element\n    ? htmx._('querySelectorExt')(elt, selector)\n    : document.querySelector(selector)\n  return resolved instanceof Element\n}\n\n/** @param {unknown} s */\nfunction asRetarget(s) {\n  return typeof s === 'string' && isResolvableRetarget(document.body, s) ? s : null\n}","tryCatchPattern":"// Recovery surface is the htmx:targetError event (fired just before the throw);\n// the throw lives in the async XHR onload, so a sync try/catch will not catch it.\ndocument.body.addEventListener('htmx:targetError', (e) => {\n  const { target } = e.detail\n  console.error('[htmx] invalid re-target', target, e.target)\n})","preventionTips":["Treat HX-Retarget and responseHandling[].target as API contract; test that each endpoint's selector is always rendered.","Prefer id selectors over class/extended selectors for retargets.","Omit HX-Retarget server-side when the target element would be absent rather than emitting a possibly-unmatched selector.","Register one global htmx:targetError listener at bootstrap so misses are logged instead of failing silently.","This file is a vendored copy of src/htmx.js — keep it in sync via the build/vendor step so source-level fixes reach the served asset; do not hand-edit it in isolation."],"tags":["htmx","retarget","hx-retarget","selector","dom","response-handling","vendored-copy"],"backgroundTag":null,"analyzedSha":"ad56dff71e55d9c717447437b4c942a64575d4b2","analyzedAt":"2026-08-13T01:40:12.610Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}