{"record":{"id":"64169d8e7616a6cc","repo":"alibaba/arthas","slug":"required-parameter-paramname-cannot-be-empty","errorCode":null,"errorMessage":"Required parameter '{paramName}' cannot be empty","messagePattern":"Required parameter '(.+?)' cannot be empty","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/tool/DefaultToolCallback.java","lineNumber":114,"sourceCode":"        Parameter[] parameters = this.toolMethod.getParameters();\n        \n        for (Parameter parameter : parameters) {\n            if (parameter.getType().isAssignableFrom(ToolContext.class)) {\n                continue;\n            }\n            \n            ToolParam toolParam = parameter.getAnnotation(ToolParam.class);\n            if (toolParam != null && toolParam.required()) {\n                String paramName = parameter.getName();\n                Object paramValue = toolArguments.get(paramName);\n                \n                // check if the parameter is empty or an empty string\n                if (paramValue == null) {\n                    throw new IllegalArgumentException(\"Required parameter '\" + paramName + \"' is missing\");\n                }\n\n                if (paramValue instanceof String && ((String) paramValue).trim().isEmpty()) {\n                    throw new IllegalArgumentException(\"Required parameter '\" + paramName + \"' cannot be empty\");\n                }\n            }\n        }\n    }\n\n    private Map<String, Object> extractToolArguments(String toolInput) {\n        return JsonParser.fromJson(toolInput, new TypeReference<Map<String, Object>>() {\n        });\n    }\n\n    private Object[] buildMethodArguments(Map<String, Object> toolInputArguments, ToolContext toolContext) {\n        return Stream.of(this.toolMethod.getParameters()).map(parameter -> {\n            if (parameter.getType().isAssignableFrom(ToolContext.class)) {\n                return toolContext;\n            }\n            Object rawArgument = toolInputArguments.get(parameter.getName());\n            return buildTypedArgument(rawArgument, parameter.getParameterizedType());\n        }).toArray();","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/alibaba/arthas/blob/21cf2e9ba52b305290be7223b980ff504bb9cb5b/arthas-mcp-server/src/main/java/com/taobao/arthas/mcp/server/tool/DefaultToolCallback.java#L96-L132","documentation":"DefaultToolCallback inspects each method parameter annotated with @ToolParam(required = true). After resolving the value from toolArguments, if the value is a String whose trimmed form is empty it throws IllegalArgumentException(\"... cannot be empty\"). A null value throws a different message (\"is missing\"), so this specific error fires only when a non-null but blank string is supplied.","triggerScenarios":"Invoking an MCP tool whose method signature has a @ToolParam(required = true) String parameter, passing a tool input JSON like {\"paramName\": \"\"} or {\"paramName\": \"   \"}.","commonSituations":"Client form sends an empty default string instead of omitting the field; JSON null-vs-empty confusion (null yields \"is missing\", not this error); whitespace-only input from a trimmed UI field; schema mismatch where the client believes the field is optional.","solutions":["Supply a non-blank value for the required parameter.","If the parameter is genuinely optional, change @ToolParam(required = false) (or remove required) in the tool method.","Trim and validate required string inputs on the client side before calling the tool."],"exampleFix":"// before\n@ToolParam(required = true) String expr;\n// caller: tool.call({\"expr\": \"\"})  -> throws\n\n// after - validate client-side and send a real value\nString e = rawExpr == null ? \"\" : rawExpr.trim();\nif (e.isEmpty()) throw new IllegalArgumentException(\"expr required\");\ntool.call(Map.of(\"expr\", e));","handlingStrategy":"validation","validationCode":"for (Map.Entry<String,Object> e : toolArguments.entrySet()) {\n    Object v = e.getValue();\n    if (v instanceof String s && s.trim().isEmpty() && isRequired(e.getKey())) {\n        throw new IllegalArgumentException(\"Required param \" + e.getKey() + \" is blank\");\n    }\n}","typeGuard":"static boolean isNonBlankRequired(Object value) {\n    return value != null && (!(value instanceof String s) || !s.trim().isEmpty());\n}","tryCatchPattern":"try {\n    callback.call(toolInput);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().endsWith(\"cannot be empty\")) {\n        // prompt user / return tool-error to client\n    } else throw e;\n}","preventionTips":["Mark only truly mandatory parameters @ToolParam(required = true).","Trim and validate required string inputs at the client before invoking.","Distinguish null (\"is missing\") from blank (\"cannot be empty\") in error handling."],"tags":["validation","mcp","tool-param","api-contract"],"backgroundTag":null,"analyzedSha":"21cf2e9ba52b305290be7223b980ff504bb9cb5b","analyzedAt":"2026-08-14T00:57:07.243Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}