First, below is the desired result without any JavaScript added
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body { display: flex; justify-content: center; align-items: center; }
svg { width: 12.5rem; height: 6rem; }
path { fill: none; stroke: #444; stroke-width: 5px; }
circle { opacity: 0.75; fill: #0dd; }
<svg>
<path
d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"
/>
<circle r='10'>
<animateMotion
dur="5s" repeatCount="indefinite"
path="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"
/>
</circle>
</svg>
Notice the animateMotion element and values of the path attribute. Everything works perfectly in the snippet above.
In the snippet below, however, we don't have the path attribute yet added on the animateMotion element so we're trying to insert it with JavaScript. In the completed program the path attribute will be filled with dynamic values.
Why doesn't the animateMotion element work here like in the first snippet when the DOM structure is identical?
let animateMotion = document.querySelector( `animateMotion` );
animateMotion.setAttributeNS(
`http://www.w3.org/2000/svg`, `path`,
`M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z`
);
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body { display: flex; justify-content: center; align-items: center; }
svg { width: 12.5rem; height: 6rem; }
path { fill: none; stroke: #444; stroke-width: 5px; }
circle { opacity: 0.75; fill: #0dd; }
<svg>
<path
d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z"
/>
<circle r='10'>
<animateMotion
dur="5s" repeatCount="indefinite"
/>
</circle>
</svg>
Upon inspection we can see the browser appears to have correctly added the path attribute exactly as it appears in the HTML of the first snippet:

Try passing null as the
namespaceinsetAttributeNS