nexu-io/open-design · error · Error
invalid data-od-repeat directive: "${directive.spec}" (expec
Error message
invalid data-od-repeat directive: "${directive.spec}" (expected "item in data.path") What it means
Thrown by renderFragment() when the contents of a data-od-repeat attribute do not match the required directive grammar: `varName in data.path`. The REPEAT_DIRECTIVE_SPEC regex demands exactly one loop variable (identifier), the literal keyword `in`, and a data-rooted dotted path (must start with `data`). Any deviation — missing `in`, missing `data.` prefix, disallowed characters, multiple variables — is rejected.
Source
Thrown at apps/daemon/src/live-artifacts/render.ts:238
}
cursor = matchEnd;
}
return null;
}
function renderFragment(html: string, resolve: BindingResolver, readArray: ArrayReader): string {
let out = '';
let cursor = 0;
while (cursor < html.length) {
const directive = findRepeatDirective(html, cursor);
if (!directive) {
out += interpolateScalars(html.slice(cursor), resolve);
break;
}
const { openTagStart, tagName } = directive;
const spec = REPEAT_DIRECTIVE_SPEC.exec(directive.spec);
if (!spec?.[1] || !spec[2]) throw new Error(`invalid data-od-repeat directive: "${directive.spec}" (expected "item in data.path")`);
const varName = spec[1];
const arrayPath = spec[2];
const openTagEnd = findTagEnd(html, openTagStart);
const selfClosed = html[openTagEnd - 1] === '/';
const elementEnd = selfClosed ? openTagEnd + 1 : findElementEnd(html, tagName, openTagEnd + 1);
const element = html.slice(openTagStart, elementEnd);
// Strip only this element's own directive from its opening tag; a REAL
// directive anywhere in what remains means a nested repeat, which the
// contract does not support. Literal mentions inside the repeated body
// stay inert — same rule as the top-level scan.
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);View on GitHub (pinned to 5be4028344)
Solutions
- Rewrite the directive as `data-od-repeat="<varName> in data.<path>"`, e.g. `data-od-repeat="item in data.items"`.
- Make sure the source path begins with `data.` and uses only allowed segment characters (letters, digits, underscore, dash; numeric indices allowed).
- Use a single loop variable name made of `[A-Za-z_][A-Za-z0-9_]*` (no dashes).
- If you need the index, expose it inside data.json (e.g. precompute `data.indexedItems` with explicit index fields) since the directive grammar does not support `(item, i) in ...`.
Example fix
// before
<li data-od-repeat="item in items">{{item.label}}</li>
// after
<li data-od-repeat="item in data.items">{{item.label}}</li> Defensive patterns
Strategy: validation
Validate before calling
const REPEAT_DIRECTIVE_SPEC = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s+in\s+(data(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*)\s*$/;
function isValidRepeatDirective(spec: string): boolean {
const m = REPEAT_DIRECTIVE_SPEC.exec(spec);
return !!m && !!m[1] && !!m[2];
}
// scan the template before rendering
for (const [, spec] of templateHtml.matchAll(/\bdata-od-repeat\s*=\s*"([^"]*)"/gi)) {
if (!isValidRepeatDirective(spec)) throw new Error(`bad directive: ${spec}`);
} Type guard
function isRepeatDirectiveSpec(spec: string): spec is `${string} in data.${string}` {
return /^\s*[A-Za-z_][A-Za-z0-9_]*\s+in\s+data(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))+\s*$/.test(spec);
} Prevention
- Always write directives as `<var> in data.<path>` with the literal `data.` prefix.
- Use a single loop variable; do not attempt `(item, idx) in ...`.
- Pre-validate agent-authored directives against the spec regex before persisting.
When it happens
Trigger: Writing `data-od-repeat="item in items"` (forgot the `data.` prefix on the source); `data-od-repeat="items"` (missing the `in` keyword); `data-od-repeat="item, idx in data.items"` (multiple loop vars not supported); `data-od-repeat="item in data.items.list"` is fine but `data-od-repeat="item-in data.items"` (dash in var name) is not.
Common situations: Developer copies a Vue (`v-for="item in items"`) or Angular (`*ngFor="let item of items"`) snippet without translating to the html_template_v1 `data.*` convention; LLM authors a directive from memory and omits the `data.` prefix; using `of` instead of `in`.
Related errors
- unterminated tag in live artifact template
- unbalanced data-od-repeat element <${tagName}>
- nested data-od-repeat is not supported
- data-od-repeat source is not an array: ${arrayPath}
- script elements are not supported in live artifact previews
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/e278044b38c245f0.
Report an issue: GitHub.