nexu-io/open-design · error · Error

raw template interpolation is not supported

Error message

raw template interpolation is not supported

What it means

Thrown by renderHtmlTemplateV1() when the template contains a raw-interpolation construct — either triple-mustache `{{{ ... }}}` or ampersand-mustache `{{& ... }}`. These are Mustache/Handlebars conventions for inserting unescaped HTML, which the live artifact renderer rejects outright as an XSS control: all scalar substitution in html_template_v1 is auto-escaped via escapeHtmlTemplateValue(), and there is no opt-out.

Source

Thrown at apps/daemon/src/live-artifacts/render.ts:269

    const itemTemplate = element.replace(REPEAT_DIRECTIVE, '');
    if (findRepeatDirective(itemTemplate)) {
      throw new Error('nested data-od-repeat is not supported');
    }

    out += interpolateScalars(html.slice(cursor, openTagStart), resolve);
    for (const item of readArray(arrayPath)) {
      out += renderFragment(itemTemplate, childResolver(resolve, varName, item), readArray);
    }
    cursor = elementEnd;
  }
  return out;
}

export function renderHtmlTemplateV1(input: LiveArtifactRenderInput): LiveArtifactRenderOutput {
  validateHtmlTemplateV1Security(input.templateHtml);

  if (RAW_TEMPLATE_INTERPOLATION.test(input.templateHtml)) {
    throw new Error('raw template interpolation is not supported');
  }

  const resolve = rootResolver(input.dataJson);
  const readArray: ArrayReader = (arrayPath) => {
    const value = readTemplatePath(input.dataJson, arrayPath);
    if (!Array.isArray(value)) throw new Error(`data-od-repeat source is not an array: ${arrayPath}`);
    return value;
  };

  return { html: renderFragment(input.templateHtml, resolve, readArray) };
}

View on GitHub (pinned to 5be4028344)

Solutions

  1. Replace raw insertion with the standard escaped form `{{data.htmlBlob}}` — the value is HTML-escaped automatically, which is the intended behavior.
  2. If you genuinely need rich HTML, pre-render it into the artifact's static preview HTML outside the template pipeline rather than injecting through a binding.
  3. Remove any stray `{{{`/`}}}` or `{{&`/`}}` tokens from the template (e.g. documentation strings that literally show the syntax).

Example fix

// before
<div>{{{data.description}}}</div>
// after
<div>{{data.description}}</div>
Defensive patterns

Strategy: validation

Validate before calling

const RAW_TEMPLATE_INTERPOLATION = /{{{[^{}]*}}}|{{\s*&[^{}]*}}/;

function assertNoRawInterpolation(templateHtml: string): void {
  if (RAW_TEMPLATE_INTERPOLATION.test(templateHtml)) {
    throw new Error('template uses raw interpolation ({{{...}}} or {{& ...}}) — convert to escaped {{...}}');
  }
}

assertNoRawInterpolation(input.templateHtml);

Prevention

When it happens

Trigger: Template.html contains `{{{data.htmlBlob}}}` or `{{& data.htmlBlob}}` intending to inject raw HTML. Also triggered by an LLM that has seen Handlebars examples and reproduces the raw-insertion syntax.

Common situations: Migrating an existing Mustache/Handlebars template into a live artifact; agent trained on templating docs emits triple-brace; developer assumes raw HTML insertion is needed for rich text and reaches for the familiar `{{{ }}}`.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/c5fc9d37aa1b4dae. Report an issue: GitHub.