siyuan-note/siyuan · error

tool is nil

Error message

tool is nil

What it means

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.

Source

Thrown at kernel/mcp/tools/validation.go:48

	maxToolSchemaBytes        = 1 << 20
	maxToolSchemaDepth        = 64
	maxToolSchemaNodes        = 16 << 10
	maxToolValueBytes         = 8 << 20
	maxToolValueDepth         = 128
	maxToolValueNodes         = 256 << 10
	toolValidationTime        = 2 * time.Second
	toolValidationConcurrency = 4
)

type ToolValidator struct {
	input           *jsonschema.Resolved
	output          *jsonschema.Resolved
	validationSlots chan struct{}
}

func CompileToolValidator(tool *Tool) (*ToolValidator, error) {
	if tool == nil {
		return nil, fmt.Errorf("tool is nil")
	}

	input, err := resolveToolSchema(tool.InputSchema, true)
	if err != nil {
		return nil, fmt.Errorf("invalid input schema: %w", err)
	}

	var output *jsonschema.Resolved
	if tool.OutputSchema != nil {
		if output, err = resolveToolSchema(*tool.OutputSchema, false); err != nil {
			return nil, fmt.Errorf("invalid output schema: %w", err)
		}
	}
	return &ToolValidator{
		input:           input,
		output:          output,
		validationSlots: make(chan struct{}, toolValidationConcurrency),
	}, nil

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure the *Tool passed to CompileToolValidator is non-nil; check the return value of whatever constructs the tool.
  2. In SetTool/buildCapabilitySet, skip or log registry entries with nil Tool instead of compiling them.
  3. Fix the upstream constructor so it returns an error rather than a nil tool.

Example fix

// before
v, err := CompileToolValidator(tool)
// after
if tool == nil {
    return fmt.Errorf("tool %q is not defined", name)
}
v, err := CompileToolValidator(tool)
Defensive patterns

Strategy: type-guard

Validate before calling

if tool == nil {
    return errors.New("cannot compile validator: tool is nil")
}

Type guard

func toolDefined(t *tools.Tool) bool { return t != nil }

Try / catch

v, err := tools.CompileToolValidator(tool)
if err != nil {
    if strings.Contains(err.Error(), "tool is nil") {
        return fmt.Errorf("tool %q missing definition", name)
    }
    return err
}

Prevention

When it happens

Trigger: Calling CompileToolValidator(nil), or calling SetTool / buildCapabilitySet with a registry entry whose Tool field is nil (e.g. a registered tool factory returned nil).

Common situations: 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.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/1715c279caa870d8. Report an issue: GitHub.