nexu-io/open-design · error · Error
invalid template binding path: ${binding}
Error message
invalid template binding path: ${binding} What it means
Thrown by rootResolver when a binding does not match TEMPLATE_PATH (/^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*$/) or does not start with 'data'. The root scope only accepts paths rooted at data.* with segments that are either identifiers (letters, digits, _, trailing - allowed) or pure-numeric array indices. Anything else — empty segments, disallowed characters, leading digits, dotted reserved words — is rejected.
Source
Thrown at apps/daemon/src/live-artifacts/render.ts:87
}
function readTemplatePath(dataJson: BoundedJsonObject, rawPath: string): unknown {
const segments = rawPath.split('.');
if (segments.shift() !== 'data') throw new Error(`unsupported template binding path: ${rawPath}`);
return walkPath(dataJson, segments, rawPath);
}
function scalarOrThrow(value: unknown, binding: string): string {
if (Array.isArray(value) || (value !== null && typeof value === 'object')) {
throw new Error(`template binding must resolve to a scalar: ${binding}`);
}
return escapeHtmlTemplateValue(value);
}
function rootResolver(dataJson: BoundedJsonObject): BindingResolver {
return (binding) => {
if (!TEMPLATE_PATH.test(binding) || !binding.startsWith('data')) {
throw new Error(`invalid template binding path: ${binding}`);
}
return scalarOrThrow(readTemplatePath(dataJson, binding), binding);
};
}
function childResolver(parent: BindingResolver, varName: string, item: unknown): BindingResolver {
return (binding) => {
if (!TEMPLATE_PATH.test(binding)) throw new Error(`invalid template binding path: ${binding}`);
const segments = binding.split('.');
if (segments[0] !== varName) return parent(binding);
return scalarOrThrow(walkPath(item, segments.slice(1), binding), binding);
};
}
function interpolateScalars(fragment: string, resolve: BindingResolver): string {
return fragment.replace(TEMPLATE_INTERPOLATION, (_match, rawBinding: string) => resolve(rawBinding.trim()));
}
View on GitHub (pinned to 5be4028344)
Solutions
- Keep segment names to identifiers matching [A-Za-z_][A-Za-z0-9_-]*; use numeric segments only for array indices.
- If a data key has an unsupported name, project/rename it in the refresh source output to a safe key.
- Use dot-only paths — no brackets, no wildcards, no array[n] syntax.
Example fix
// before
<div>{{data.repo.0-full-name}}</div>
// after
<div>{{data.repo.full_name}}</div> Defensive patterns
Strategy: validation
Validate before calling
const TEMPLATE_PATH = /^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*$/;
function assertValidBinding(b: string): void {
if (!TEMPLATE_PATH.test(b) || !b.startsWith('data')) throw new Error(`invalid binding: ${b}`);
} Type guard
function isValidRootBinding(b: string): boolean {
return /^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\.(?:[A-Za-z_][A-Za-z0-9_-]*|\d+))*$/.test(b) && b.startsWith('data');
} Prevention
- Restrict segment names to identifiers; project odd-named data keys to safe names upstream.
- No brackets, no wildcards, no empty segments.
- Lint bindings against TEMPLATE_PATH during authoring.
When it happens
Trigger: {{data.foo-bar.baz}} where a segment starts with a hyphen; {{data.1x}} (segment starting with digit but not a pure integer); {{data.a.}} (trailing dot, empty segment); {{data..x}}; {{DATA.title}} (case-sensitive head); bindings starting with a reserved word that isn't 'data'.
Common situations: Field names from the refresh source contain characters the DSL doesn't allow (e.g. data keys with leading digits or unusual punctuation); model invents a path syntax (e.g. array[n] bracket syntax); typo introducing an empty segment; uppercase DATA vs data.
Related errors
- invalid array segment in template binding path: ${rawPath}
- unsupported template binding path: ${rawPath}
- template binding must resolve to a scalar: ${binding}
- connector refresh source requires connector metadata
- ${field} must be a dot-separated JSON path
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/a6eebfc411e997f3.
Report an issue: GitHub.