{"record":{"id":"885966d469fd6196","repo":"JuliusBrussee/caveman","slug":"tool-schema-transform-invalid","errorCode":"tool_schema_transform_invalid","errorMessage":"tool_schema_transform_invalid:${segmentID}","messagePattern":"tool_schema_transform_invalid:(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":3804,"sourceCode":"              : \"Use cave_retrieve for omitted detail.\",\n          ].join(\"\\n\"),\n        }],\n        details: {\n          effect: definition.effect,\n          resultPolicy: definition.result,\n          recoveryHandle: transformed.handle,\n          recoveryVerified: true,\n        },\n      };\n    },\n  };\n}\n\nfunction validatedToolSchemaBytes(output: Uint8Array, segmentID: string): Uint8Array {\n  const parsed = JSON.parse(new TextDecoder().decode(output)) as unknown;\n  if (!isRecord(parsed) || typeof parsed.name !== \"string\" ||\n      typeof parsed.description !== \"string\" || !isRecord(parsed.input)) {\n    throw new Error(`tool_schema_transform_invalid:${segmentID}`);\n  }\n  return output;\n}\n\nfunction providerToolDefinition(\n  definition: ToolDefinition,\n  lowered: LoweredContext,\n  appliedPlan: AppliedPlan,\n): { description: string; input: TSchema } {\n  const segment = lowered.ir.segments.find((item) => item.id === `tool.${definition.name}`);\n  if (!segment) throw new Error(`cave_context_segment_missing:tool.${definition.name}`);\n  const body = appliedPlan.bodies.get(segment.bodyHandle);\n  if (!body) throw new Error(`cave_context_body_missing:tool.${definition.name}`);\n  const parsed = JSON.parse(new TextDecoder().decode(body)) as unknown;\n  if (!isRecord(parsed) || parsed.name !== definition.name ||\n      typeof parsed.description !== \"string\" || !isRecord(parsed.input)) {\n    throw new Error(`cave_tool_schema_invalid:${definition.name}`);\n  }","sourceCodeStart":3786,"sourceCodeEnd":3822,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L3786-L3822","documentation":"validatedToolSchemaBytes parses bytes produced by a schema transform and requires a record with string \"name\", string \"description\", and record \"input\". Anything else means the transform emitted an invalid tool schema, and the segment ID is included in the message to identify which tool failed.","triggerScenarios":"A schema transform output for segment segmentID fails JSON.parse or the parsed object lacks name:string, description:string, or a record-shaped input at runtime.ts:3804.","commonSituations":"A custom transform/plugin emitting the wrong shape; an upstream provider schema change; a tool registered without a description; transform output being truncated or double-encoded.","solutions":["Inspect the transform that produced the segment and ensure it emits { name, description, input } with correct types.","Add the missing description/input fields to the tool definition that feeds the transform.","Log the raw transform output before validation to see what actually came out.","If using a third-party transform, check its version against the runtime's expected schema."],"exampleFix":"// before: transform output missing description\nJSON.stringify({ name: \"search\", input: searchSchema })\n// after\nJSON.stringify({ name: \"search\", description: \"Search the index\", input: searchSchema })","handlingStrategy":"type-guard","validationCode":"function isValidTransformedSchema(v: unknown): boolean {\n  return !!v && typeof v === 'object' && typeof (v as any).name === 'string' &&\n    typeof (v as any).description === 'string' &&\n    !!(v as any).input && typeof (v as any).input === 'object';\n}","typeGuard":"const isRecord = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);\nfunction validToolSchema(v: unknown): v is { name: string; description: string; input: Record<string, unknown> } {\n  return isRecord(v) && typeof v.name === 'string' && typeof v.description === 'string' && isRecord(v.input);\n}","tryCatchPattern":"try {\n  return validatedToolSchemaBytes(output, segmentID);\n} catch (e) {\n  if (String(e?.message).startsWith('tool_schema_transform_invalid')) {\n    console.error(`transform for ${segmentID} emitted invalid schema`);\n  }\n  throw e;\n}","preventionTips":["Unit-test every custom transform's output against the { name, description, input } shape.","Never register tools without a description.","Log raw transform output during schema development."],"tags":["schema-validation","tool-schema","transform"],"backgroundTag":"schema-validation-failed","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}