{"record":{"id":"443cfa15ce39ed43","repo":"JuliusBrussee/caveman","slug":"cave-plan-route-unmatched-route-segment-id-ro","errorCode":null,"errorMessage":"cave_plan_route_unmatched:${route.segment_id ?? route.segment_kind}","messagePattern":"cave_plan_route_unmatched:(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":2640,"sourceCode":"  ].map((name) => `caveman.engine.${name}.v1`));\n  const evaluated: string[] = [];\n  const applied: string[] = [];\n  const failures: string[] = [];\n  const handles = new Set<string>();\n  const trace: MutableTransformTrace[] = [];\n  let recoveryResolved = true;\n  for (const route of plan.segment_routes) {\n    if (!known.has(route.transform_id)) {\n      throw new Error(`cave_unknown_transform:${route.transform_id}`);\n    }\n    const targets = lowered.ir.segments.filter((segment) =>\n      segment.kind === route.segment_kind &&\n      (route.segment_id === undefined || segment.id === route.segment_id));\n    if (targets.length === 0) {\n      if (route.segment_kind === \"history\" || route.segment_kind === \"tool_result\") {\n        continue;\n      }\n      throw new Error(`cave_plan_route_unmatched:${route.segment_id ?? route.segment_kind}`);\n    }\n    evaluated.push(route.transform_id);\n    let routeApplied = false;\n    for (const segment of targets) {\n      const original = lowered.bodies.get(segment.bodyHandle);\n      if (!original) throw new Error(`cave_context_body_missing:${segment.id}`);\n      if (segment.safety !== \"S4\") throw new Error(`cave_transform_safety_mismatch:${segment.id}`);\n      const startedAt = performance.now();\n      // beforeTokens/afterTokens are byte-derived (bytes/4) throughout so a\n      // delta is always within one basis. beforeTokens counts the ORIGINAL\n      // bytes; afterTokens, for an applied transform, counts the FULL provider\n      // body actually sent — wrapper included. segment.tokenCount\n      // is already estimateTokens(original) = bytes/4.\n      const beforeTokens = segment.tokenCount;\n      if (segment.opaque) {\n        trace.push({\n          segmentKind: segment.kind,\n          transformID: route.transform_id,","sourceCodeStart":2622,"sourceCodeEnd":2658,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/runtime.ts#L2622-L2658","documentation":"Thrown when a plan route matches zero segments in the lowered IR. Routes targeting history or tool_result kinds are tolerated (they may legitimately match nothing and 'continue'), but any other unmatched route is an error: the plan does not correspond to this context.","triggerScenarios":"A route's segment_kind/segment_id filter matches no segments — e.g. the plan was built for a different agent definition, a segment id was renamed, or the context composition changed after the plan was made. Only non-history, non-tool_result kinds throw.","commonSituations":"Reusing a cached plan across agent definitions or prompt revisions; renamed context segment ids; plan/context version skew.","solutions":["Regenerate the plan against the current lowered context","If the id in the error message was renamed, update the plan to the new segment id","Invalidate cached plans whenever the agent definition or contexts change"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"function planRoutesMatch(plan: CavePlan, lowered: LoweredContext): boolean {\n  return plan.segment_routes.every((route) => {\n    const hits = lowered.ir.segments.filter((s) =>\n      s.kind === route.segment_kind &&\n      (route.segment_id === undefined || s.id === route.segment_id));\n    return hits.length > 0 || route.segment_kind === \"history\" || route.segment_kind === \"tool_result\";\n  });\n}","typeGuard":"function planRouteUnmatched(e: unknown): string | null {\n  if (!(e instanceof Error)) return null;\n  const m = /^cave_plan_route_unmatched:(.+)$/.exec(e.message);\n  return m ? m[1] : null;\n}","tryCatchPattern":"if (!planRoutesMatch(plan, lowered)) {\n  plan = await buildPlan(lowered); // plan and context must come from the same state\n}\nawait applyPlan(plan, lowered);","preventionTips":["Never reuse a plan across definition or context revisions","Regenerate plans in the same pipeline stage that lowers contexts","Rename segment ids in plans and definitions together"],"tags":["plan","transforms","version-skew"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}