{"record":{"id":"779e20539e7448fc","repo":"nexu-io/open-design","slug":"firstissue-path-firstissue-message","errorCode":null,"errorMessage":"${firstIssue.path}: ${firstIssue.message}","messagePattern":"\\$\\{firstIssue\\.path\\}: \\$\\{firstIssue\\.message\\}","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/daemon/src/live-artifacts/refresh.ts","lineNumber":271,"sourceCode":"    throw toRefreshAbortError(error, run);\n  } finally {\n    clearTimeout(sourceTimeout);\n    run.signal.removeEventListener('abort', onRunAbort);\n  }\n}\n\nfunction isLocalDaemonRefreshToolName(value: string | undefined): value is LocalDaemonRefreshToolName {\n  return value === 'project_files.search'\n    || value === 'project_files.read_json'\n    || value === 'git.summary'\n    || value === 'public_github_repository_metric';\n}\n\nfunction asBoundedRefreshOutput(value: BoundedJsonObject): BoundedJsonObject {\n  const result = validateBoundedJsonObject(value, 'localRefreshOutput');\n  if (!result.ok) {\n    const firstIssue = result.issues[0];\n    throw new Error(firstIssue === undefined ? result.error : `${firstIssue.path}: ${firstIssue.message}`);\n  }\n  return result.value;\n}\n\nconst SAFE_MAPPING_SEGMENT = /^[A-Za-z_][A-Za-z0-9_-]*$|^(?:0|[1-9][0-9]*)$/;\nconst UNSAFE_MAPPING_SEGMENTS = new Set(['__proto__', 'prototype', 'constructor']);\n\nfunction parseMappingPath(path: string, field: string): string[] {\n  const normalized = path.startsWith('$.') ? path.slice(2) : path;\n  if (normalized.length === 0 || normalized.startsWith('.') || normalized.endsWith('.') || normalized.includes('..')) {\n    throw new Error(`${field} must be a dot-separated JSON path`);\n  }\n  const segments = normalized.split('.');\n  for (const segment of segments) {\n    if (!SAFE_MAPPING_SEGMENT.test(segment) || UNSAFE_MAPPING_SEGMENTS.has(segment)) {\n      throw new Error(`${field} contains unsupported JSON path segment: ${segment}`);\n    }\n  }","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/live-artifacts/refresh.ts#L253-L289","documentation":"asBoundedRefreshOutput (refresh.ts:267-273) runs validateBoundedJsonObject(value, 'localRefreshOutput') on every refresh output before it is merged into the artifact dataJson. Bounded-JSON enforces structural caps (max depth, max string length, max array length, max object key count). If validation fails, the first issue's path and message are thrown so the caller knows exactly where the limit was exceeded.","triggerScenarios":"A daemon_tool or connector refresh output (or a transformed/mapped output) violates a bounded-JSON constraint — e.g. an object nested too deeply, a string longer than the cap, or an array with too many entries.","commonSituations":"project_files.read_json on a very large or deeply nested JSON file; a git.summary whose recentCommits/diffStat arrays are large; a connector returning a huge payload; an outputMapping transform (compact_table/metric_summary) that still exceeds caps.","solutions":["Reduce the size or depth of the source output (smaller file, fewer commits, narrower connector query).","For read_json, point input.path at a smaller slice of data or a pre-summarized file.","Add an outputMapping.dataPaths to extract only the needed fields before they hit bounded-JSON validation."],"exampleFix":"// before: refresh reads a deeply nested 2MB JSON file\n// asBoundedRefreshOutput throws `$.deeply.nested.path: exceeds max depth`\n\n// after: add outputMapping.dataPaths to keep only flat fields\nconst source = {\n  type: 'daemon_tool',\n  toolName: 'project_files.read_json',\n  input: { path: 'data.json' },\n  outputMapping: { dataPaths: [{ from: 'summary.total', to: 'summary.total' }] }\n};","handlingStrategy":"validation","validationCode":"import { validateBoundedJsonObject } from './schema.js'; // conceptually\nfunction assertBoundedRefreshOutput(value: BoundedJsonObject): void {\n  const r = validateBoundedJsonObject(value, 'localRefreshOutput');\n  if (!r.ok) throw new Error(`${r.issues[0]?.path ?? '<root>'}: ${r.issues[0]?.message ?? r.error}`);\n}\n// call this on a sample output before wiring it as a refresh source","typeGuard":"function isBoundedRefreshOutput(value: unknown): boolean {\n  const r = validateBoundedJsonObject(value as BoundedJsonObject, 'localRefreshOutput');\n  return r.ok;\n}","tryCatchPattern":"try {\n  await refreshLiveArtifact(opts);\n} catch (err) {\n  if (err instanceof Error && /localRefreshOutput|exceeds/.test(err.message)) {\n    // suggest reducing file size / adding outputMapping\n  }\n  throw err;\n}","preventionTips":["Keep refresh source outputs small and shallow; prefer flat summaries over raw dumps.","Add outputMapping.dataPaths to extract only required fields.","For project_files.read_json, target files well under 256 KiB and avoid deep nesting."],"tags":["live-artifacts","refresh","bounded-json","json-validation"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}