{"record":{"id":"1715c279caa870d8","repo":"siyuan-note/siyuan","slug":"tool-is-nil","errorCode":null,"errorMessage":"tool is nil","messagePattern":"tool is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mcp/tools/validation.go","lineNumber":48,"sourceCode":"\tmaxToolSchemaBytes        = 1 << 20\n\tmaxToolSchemaDepth        = 64\n\tmaxToolSchemaNodes        = 16 << 10\n\tmaxToolValueBytes         = 8 << 20\n\tmaxToolValueDepth         = 128\n\tmaxToolValueNodes         = 256 << 10\n\ttoolValidationTime        = 2 * time.Second\n\ttoolValidationConcurrency = 4\n)\n\ntype ToolValidator struct {\n\tinput           *jsonschema.Resolved\n\toutput          *jsonschema.Resolved\n\tvalidationSlots chan struct{}\n}\n\nfunc CompileToolValidator(tool *Tool) (*ToolValidator, error) {\n\tif tool == nil {\n\t\treturn nil, fmt.Errorf(\"tool is nil\")\n\t}\n\n\tinput, err := resolveToolSchema(tool.InputSchema, true)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid input schema: %w\", err)\n\t}\n\n\tvar output *jsonschema.Resolved\n\tif tool.OutputSchema != nil {\n\t\tif output, err = resolveToolSchema(*tool.OutputSchema, false); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid output schema: %w\", err)\n\t\t}\n\t}\n\treturn &ToolValidator{\n\t\tinput:           input,\n\t\toutput:          output,\n\t\tvalidationSlots: make(chan struct{}, toolValidationConcurrency),\n\t}, nil","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/mcp/tools/validation.go#L30-L66","documentation":"CompileToolValidator refuses to build a validator when the *Tool pointer is nil. This library compiles JSON-Schema validators for MCP tools, and validating a nil tool has no meaningful schema, so it fails fast with a clear error instead of panicking later on a nil dereference. It is a defensive guard at the entry of validator compilation.","triggerScenarios":"Calling CompileToolValidator(nil), or calling SetTool / buildCapabilitySet with a registry entry whose Tool field is nil (e.g. a registered tool factory returned nil).","commonSituations":"Constructing tool sets dynamically where a builder function returns nil on some branch; refactoring that removed a tool but left its registration slot; deserializing tool definitions where a missing entry decodes to nil.","solutions":["Ensure the *Tool passed to CompileToolValidator is non-nil; check the return value of whatever constructs the tool.","In SetTool/buildCapabilitySet, skip or log registry entries with nil Tool instead of compiling them.","Fix the upstream constructor so it returns an error rather than a nil tool."],"exampleFix":"// before\nv, err := CompileToolValidator(tool)\n// after\nif tool == nil {\n    return fmt.Errorf(\"tool %q is not defined\", name)\n}\nv, err := CompileToolValidator(tool)","handlingStrategy":"type-guard","validationCode":"if tool == nil {\n    return errors.New(\"cannot compile validator: tool is nil\")\n}","typeGuard":"func toolDefined(t *tools.Tool) bool { return t != nil }","tryCatchPattern":"v, err := tools.CompileToolValidator(tool)\nif err != nil {\n    if strings.Contains(err.Error(), \"tool is nil\") {\n        return fmt.Errorf(\"tool %q missing definition\", name)\n    }\n    return err\n}","preventionTips":["Never allow tool factories to return nil without an error","Check for nil immediately after decoding/deserializing tool definitions","Add a nil check in registration wrappers before calling CompileToolValidator"],"tags":["go","nil-pointer","mcp-tools"],"backgroundTag":"null-argument","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}