{"record":{"id":"a6eebfc411e997f3","repo":"nexu-io/open-design","slug":"invalid-template-binding-path-binding","errorCode":null,"errorMessage":"invalid template binding path: ${binding}","messagePattern":"invalid template binding path: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/live-artifacts/render.ts","lineNumber":87,"sourceCode":"}\n\nfunction readTemplatePath(dataJson: BoundedJsonObject, rawPath: string): unknown {\n  const segments = rawPath.split('.');\n  if (segments.shift() !== 'data') throw new Error(`unsupported template binding path: ${rawPath}`);\n  return walkPath(dataJson, segments, rawPath);\n}\n\nfunction scalarOrThrow(value: unknown, binding: string): string {\n  if (Array.isArray(value) || (value !== null && typeof value === 'object')) {\n    throw new Error(`template binding must resolve to a scalar: ${binding}`);\n  }\n  return escapeHtmlTemplateValue(value);\n}\n\nfunction rootResolver(dataJson: BoundedJsonObject): BindingResolver {\n  return (binding) => {\n    if (!TEMPLATE_PATH.test(binding) || !binding.startsWith('data')) {\n      throw new Error(`invalid template binding path: ${binding}`);\n    }\n    return scalarOrThrow(readTemplatePath(dataJson, binding), binding);\n  };\n}\n\nfunction childResolver(parent: BindingResolver, varName: string, item: unknown): BindingResolver {\n  return (binding) => {\n    if (!TEMPLATE_PATH.test(binding)) throw new Error(`invalid template binding path: ${binding}`);\n    const segments = binding.split('.');\n    if (segments[0] !== varName) return parent(binding);\n    return scalarOrThrow(walkPath(item, segments.slice(1), binding), binding);\n  };\n}\n\nfunction interpolateScalars(fragment: string, resolve: BindingResolver): string {\n  return fragment.replace(TEMPLATE_INTERPOLATION, (_match, rawBinding: string) => resolve(rawBinding.trim()));\n}\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/live-artifacts/render.ts#L69-L105","documentation":"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.","triggerScenarios":"{{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'.","commonSituations":"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.","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."],"exampleFix":"// before\n<div>{{data.repo.0-full-name}}</div>\n// after\n<div>{{data.repo.full_name}}</div>","handlingStrategy":"validation","validationCode":"const TEMPLATE_PATH = /^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\\.(?:[A-Za-z_][A-Za-z0-9_-]*|\\d+))*$/;\nfunction assertValidBinding(b: string): void {\n  if (!TEMPLATE_PATH.test(b) || !b.startsWith('data')) throw new Error(`invalid binding: ${b}`);\n}","typeGuard":"function isValidRootBinding(b: string): boolean {\n  return /^(?:data|[A-Za-z_][A-Za-z0-9_]*)(?:\\.(?:[A-Za-z_][A-Za-z0-9_-]*|\\d+))*$/.test(b) && b.startsWith('data');\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["template-binding","path-resolution","regex","live-artifacts","validation"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}