{"record":{"id":"7123bdf680ced644","repo":"github/copilot-sdk","slug":"handler-must-not-be-null-for-tool-toolname","errorCode":null,"errorMessage":"handler must not be null for tool ' + toolName + '","messagePattern":"handler must not be null for tool ' \\+ toolName \\+ '","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/rpc/ToolDefinition.java","lineNumber":920,"sourceCode":"    // ------------------------------------------------------------------\n    // Validation helpers\n    // ------------------------------------------------------------------\n\n    private static void requireNonBlankToolName(String name) {\n        if (name == null || name.isBlank()) {\n            throw new IllegalArgumentException(\"Tool name must not be null or blank\");\n        }\n    }\n\n    private static void requireNonBlankDescription(String description) {\n        if (description == null || description.isBlank()) {\n            throw new IllegalArgumentException(\"Tool description must not be null or blank\");\n        }\n    }\n\n    private static void requireNonNullHandler(Object handler, String toolName) {\n        if (handler == null) {\n            throw new IllegalArgumentException(\"handler must not be null for tool '\" + toolName + \"'\");\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private static List<ToolDefinition> loadDefinitions(Class<?> clazz, Object instance) {\n        String metaClassName = clazz.getName() + \"$$CopilotToolMeta\";\n        try {\n            Class<?> metaClass = Class.forName(metaClassName, true, clazz.getClassLoader());\n            var provider = (com.github.copilot.tool.CopilotToolMetadataProvider<Object>) metaClass\n                    .getDeclaredConstructor().newInstance();\n            return provider.definitions(instance, getConfiguredMapper());\n        } catch (ClassNotFoundException e) {\n            throw new IllegalStateException(\"Generated class \" + metaClassName + \" not found. \"\n                    + \"Ensure the CopilotToolProcessor annotation processor ran during compilation. \"\n                    + \"Add the copilot-sdk-java dependency to your annotation processor path.\", e);\n        } catch (ReflectiveOperationException e) {\n            throw new IllegalStateException(\"Failed to invoke \" + metaClassName + \".definitions()\", e);\n        }","sourceCodeStart":902,"sourceCodeEnd":938,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/rpc/ToolDefinition.java#L902-L938","documentation":"A ToolDefinition must have an actual handler to execute when the tool is invoked; a null handler would produce a tool that cannot run. requireNonNullHandler throws this IllegalArgumentException when the handler argument to a from* factory is null, including the tool name in the message to help locate the offending registration.","triggerScenarios":"Calling ToolDefinition.from/fromAsync/fromWithToolInvocation/fromAsyncWithToolInvocation with a null handler — typically a method reference or lambda expression that resolved to null, or a nullable field/config-supplied handler.","commonSituations":"Spring/DI wiring where the handler bean is null at registration time; conditionally-initialized handlers (e.g. behind a feature flag) that were never created; passing a static method reference from a class that failed to load; storing handlers in a map and looking up a missing key.","solutions":["Pass a non-null handler (lambda, method reference, or Function/BiFunction) for each tool registration.","Null-check the handler (or assert bean presence) before calling the from* method and fail fast with context.","Fix DI/initialization ordering so the handler object exists before ToolDefinition registration runs."],"exampleFix":"// before\nFunction<String, String> h = handlers.get(\"search\"); // null if missing\nToolDefinition.from(\"search\", \"Search docs\", h);\n\n// after\nFunction<String, String> h = Objects.requireNonNull(handlers.get(\"search\"), \"missing search handler\");\nToolDefinition.from(\"search\", \"Search docs\", h);","handlingStrategy":"type-guard","validationCode":"Objects.requireNonNull(handler, \"handler must not be null\");","typeGuard":"static boolean hasHandler(Object handler) { return handler != null; }","tryCatchPattern":"try { return ToolDefinition.from(name, desc, handler); } catch (IllegalArgumentException e) {\n  log.error(\"registration for tool '{}' failed: {}\", name, e.getMessage()); throw e;\n}","preventionTips":["Wire handlers via DI and verify bean presence at startup.","Avoid nullable map lookups for handlers — use getOrDefault or explicit checks.","Register tools in an initialization phase where missing handlers fail fast, not lazily."],"tags":["java","validation","null-check","tool-registration"],"backgroundTag":"null-argument","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}