nexu-io/open-design · error · Error

data-od-repeat source is not an array: ${arrayPath}

Error message

data-od-repeat source is not an array: ${arrayPath}

What it means

Thrown by the readArray closure inside renderHtmlTemplateV1() when the data-od-repeat source path resolves to a value that is not an Array. readTemplatePath() walks the data.json object for the path; if the resulting value is anything other than an Array (string, number, object, null, undefined), the repeat cannot iterate and the renderer aborts. An undefined/missing path resolves to '' (empty string) via walkPath, which is also not an array.

Source

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

    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. Open data.json and confirm the path resolves to a JSON array; fix the path in the directive to match the real location of the array.
  2. If the array is legitimately optional, guard by ensuring data.json always provides an empty array `[]` for that key rather than omitting it.
  3. Validate the data.json shape against the template's expected schema before persisting the artifact.
  4. If you intended to iterate a non-array, restructure data.json to wrap the value(s) in an array.

Example fix

// before — data.json: { "data": { "title": "Hello" } }, template: <li data-od-repeat="x in data.title">{{x}}</li>
// after — data.json: { "data": { "items": ["Hello"] } }, template: <li data-od-repeat="x in data.items">{{x}}</li>
Defensive patterns

Strategy: validation

Validate before calling

function readTemplatePath(dataJson: unknown, rawPath: string): unknown {
  const segments = rawPath.split('.');
  if (segments.shift() !== 'data') throw new Error(`path must start with data.`);
  let cur: unknown = dataJson;
  for (const seg of segments) cur = (cur as Record<string, unknown>)?.[seg];
  return cur;
}

// Pre-check every repeat directive's source is an array before rendering.
for (const [, path] of templateHtml.matchAll(/\bdata-od-repeat\s*=\s*"[A-Za-z_][A-Za-z0-9_]*\s+in\s+(data[\w.-]*)"/gi)) {
  if (!Array.isArray(readTemplatePath(dataJson, path))) {
    throw new Error(`repeat source ${path} is not an array`);
  }
}

Type guard

function isArrayPath(dataJson: unknown, path: string): boolean {
  const segments = path.split('.');
  if (segments.shift() !== 'data') return false;
  let cur: unknown = dataJson;
  for (const seg of segments) cur = (cur as Record<string, unknown>)?.[seg];
  return Array.isArray(cur);
}

Prevention

When it happens

Trigger: Pointing the repeat at a scalar field: `data-od-repeat="item in data.title"` where `data.title` is a string. Pointing at an object: `data-od-repeat="item in data.config"`. Pointing at a path that does not exist in data.json (resolves to '', not an array). Pointing at null.

Common situations: Schema drift between the agent's mental model and the actual data.json shape; typo in the path; data field renamed but template not updated; data.json missing the expected array key because the upstream producer emitted an error object instead.

Related errors


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