{"record":{"id":"564edff88b400b3c","repo":"github/copilot-sdk","slug":"tool-description-must-not-be-null-or-blank","errorCode":null,"errorMessage":"Tool description must not be null or blank","messagePattern":"Tool description must not be null or blank","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/rpc/ToolDefinition.java","lineNumber":914,"sourceCode":"            return mapper.writeValueAsString(result);\n        } catch (com.fasterxml.jackson.core.JsonProcessingException ex) {\n            throw new IllegalStateException(\"Failed to serialize tool result to JSON\", ex);\n        }\n    }\n\n    // ------------------------------------------------------------------\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) {","sourceCodeStart":896,"sourceCodeEnd":932,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/rpc/ToolDefinition.java#L896-L932","documentation":"Tool descriptions are sent to the LLM so it can decide when/how to call a tool; a null or blank description yields an unusable tool. requireNonBlankDescription throws this IllegalArgumentException when the description supplied to any of the from* factory methods is null or whitespace-only.","triggerScenarios":"Calling ToolDefinition.from/fromAsync/fromWithToolInvocation/fromAsyncWithToolInvocation with description null, \"\", or \"   \" — often a variable populated from config or a missing constant.","commonSituations":"Programmatic tool registration from a config file where the description field is absent; leaving description empty while scaffolding a new tool; i18n resource missing so the lookup returns empty string.","solutions":["Provide a concise non-empty description of what the tool does to the from* call.","If the description comes from configuration/resources, validate non-blank before registering.","Use the @CopilotTool(description=...) attribute or fromObject/fromClass so descriptions come from annotations consistently."],"exampleFix":"// before\nToolDefinition.from(\"search\", \"\", handler);\n\n// after\nToolDefinition.from(\"search\", \"Searches indexed documents for a keyword query and returns matches.\", handler);","handlingStrategy":"validation","validationCode":"if (description == null || description.isBlank()) throw new IllegalArgumentException(\"tool description required\");","typeGuard":null,"tryCatchPattern":"try { return ToolDefinition.from(name, desc, handler); } catch (IllegalArgumentException e) {\n  log.error(\"tool '{}' rejected: {}\", name, e.getMessage()); throw e;\n}","preventionTips":["Always write a one-sentence behavioral description when registering a tool.","Centralize tool registration in one factory that enforces name+description checks.","For annotation-based tools, always set @CopilotTool(description=...)."],"tags":["java","validation","tool-registration"],"backgroundTag":"empty-required-field","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"}