JuliusBrussee/caveman · error

cave_plan_route_unmatched

cave_plan_route_unmatched

Error message

cave_plan_route_unmatched:${route.segment_id ?? route.segment_kind}

What it means

Thrown when a compaction plan route matches no segments in the lowered IR. Routes targeting 'history' or 'tool_result' kinds silently skip (continue), but any other route whose segment_kind (or segment_id) matches zero segments is a hard error — the plan promised to touch context that does not exist.

Solutions

  1. Remove the route from the plan, or change its segment_kind/segment_id to one that exists in the IR.
  2. Enumerate lowered.ir.segments (id/kind) and rewrite the plan to target actual segments.
  3. Make plan generation derive routes from the definition's declared contexts instead of using a static plan.
  4. If the route is intentionally optional, target only history/tool_result kinds, which the runtime skips when unmatched.

Example fix

// before
segment_routes: [{ segment_kind: "memory", transform_id: "..." }] // agent has no memory segments
// after
segment_routes: [{ segment_kind: "history", transform_id: "..." }]
Defensive patterns

Strategy: validation

Validate before calling

for (const route of plan.segment_routes) {
  const matched = lowered.ir.segments.filter(s => s.kind === route.segment_kind && (route.segment_id === undefined || s.id === route.segment_id));
  if (matched.length === 0 && route.segment_kind !== "history" && route.segment_kind !== "tool_result") {
    console.warn(`route ${route.transform_id} matches nothing (${route.segment_id ?? route.segment_kind})`);
  }
}

Type guard

function routeMatchesSomething(route: { segment_kind: string; segment_id?: string }, segments: { id: string; kind: string }[]): boolean {
  return segments.some(s => s.kind === route.segment_kind && (route.segment_id === undefined || s.id === route.segment_id));
}

Try / catch

try {
  await executePlan(plan, lowered);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("cave_plan_route_unmatched:")) {
    const target = err.message.split(":").slice(1).join(":");
    // drop the route or retarget it to an existing segment
  } else throw err;
}

Prevention

When it happens

Trigger: A plan route with segment_kind other than history/tool_result (e.g. 'context', 'memory') where the IR contains no segments of that kind, or a route with a specific segment_id that doesn't exist in lowered.ir.segments.

Common situations: A generic plan applied to an agent definition that lacks that segment type (no memory configured, say); a plan referencing a context id that was renamed or removed; running the same plan across different agents with different context shapes.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/c5a5bc466b231bbe. Report an issue: GitHub.

Appendix: source

Thrown at packages/agent/src/runtime.ts:2640

  ].map((name) => `caveman.engine.${name}.v1`));
  const evaluated: string[] = [];
  const applied: string[] = [];
  const failures: string[] = [];
  const handles = new Set<string>();
  const trace: MutableTransformTrace[] = [];
  let recoveryResolved = true;
  for (const route of plan.segment_routes) {
    if (!known.has(route.transform_id)) {
      throw new Error(`cave_unknown_transform:${route.transform_id}`);
    }
    const targets = lowered.ir.segments.filter((segment) =>
      segment.kind === route.segment_kind &&
      (route.segment_id === undefined || segment.id === route.segment_id));
    if (targets.length === 0) {
      if (route.segment_kind === "history" || route.segment_kind === "tool_result") {
        continue;
      }
      throw new Error(`cave_plan_route_unmatched:${route.segment_id ?? route.segment_kind}`);
    }
    evaluated.push(route.transform_id);
    let routeApplied = false;
    for (const segment of targets) {
      const original = lowered.bodies.get(segment.bodyHandle);
      if (!original) throw new Error(`cave_context_body_missing:${segment.id}`);
      if (segment.safety !== "S4") throw new Error(`cave_transform_safety_mismatch:${segment.id}`);
      const startedAt = performance.now();
      // beforeTokens/afterTokens are byte-derived (bytes/4) throughout so a
      // delta is always within one basis. beforeTokens counts the ORIGINAL
      // bytes; afterTokens, for an applied transform, counts the FULL provider
      // body actually sent — wrapper included. segment.tokenCount
      // is already estimateTokens(original) = bytes/4.
      const beforeTokens = segment.tokenCount;
      if (segment.opaque) {
        trace.push({
          segmentKind: segment.kind,
          transformID: route.transform_id,

View on GitHub (pinned to 3ee70a1026)