{"record":{"id":"2fbc3782a1aa3f4a","repo":"mvanhorn/last30days-skill","slug":"s-is-required","errorCode":null,"errorMessage":"%s is required","messagePattern":"(.+?) is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mcp/internal/tools/research.go","lineNumber":108,"sourceCode":"\trunArgs := []string{topic, \"--emit=\" + emit, \"--no-browser-cookies\"}\n\tif save {\n\t\trunArgs = append(runArgs, \"--save-dir\", mcpSaveDir())\n\t}\n\treturn runArgs\n}\n\nfunc mcpSaveDir() string {\n\tsaveDir := os.Getenv(\"LAST30DAYS_MEMORY_DIR\")\n\tif saveDir == \"\" {\n\t\treturn \"~/Documents/Last30Days\"\n\t}\n\treturn saveDir\n}\n\nfunc requireString(args map[string]any, name string) (string, error) {\n\traw, ok := args[name]\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"%s is required\", name)\n\t}\n\tvalue, ok := raw.(string)\n\tif !ok || strings.TrimSpace(value) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%s must be a non-empty string\", name)\n\t}\n\treturn value, nil\n}\n\nfunc emitArgument(args map[string]any) (string, error) {\n\traw, ok := args[\"emit\"]\n\tif !ok {\n\t\treturn \"compact\", nil\n\t}\n\tvalue, ok := raw.(string)\n\tif !ok {\n\t\treturn \"\", errors.New(\"emit must be a string\")\n\t}\n\tswitch value {","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/mcp/internal/tools/research.go#L90-L126","documentation":"Thrown by requireString (mcp/internal/tools/research.go:108) when a required argument key is entirely absent from the tool-call arguments map. In practice the only required string is 'topic' on the 'research' tool, so the user-facing message is \"topic is required\". This fires before any engine work happens: it is a cheap presence check distinct from the follow-up check that the value is a non-empty string. The tool schema marks topic with mcplib.Required(), so well-behaved clients should be prevented from sending the call at all.","triggerScenarios":"Calling the MCP 'research' tool with an arguments map that has no \"topic\" key at all — e.g. {} or {\"emit\": \"html\"}. Happens with hand-rolled JSON-RPC clients, a model omitting the parameter, or code that builds arguments dynamically and skips the key on an empty input instead of passing an empty string (which would produce the different 'must be a non-empty string' error).","commonSituations":"Direct JSON-RPC/mcp-go callers bypassing schema validation; agent models calling research with only optional flags; scripts that conditionally add keys and accidentally never set topic; test harnesses constructing argument maps by hand.","solutions":["Include a non-empty \"topic\" string in the research tool arguments: {\"topic\": \"OpenAI GPT-5\"}.","If building arguments programmatically, default the topic from user input and fail early in your own code with a clearer message before calling the tool.","Client authors: honor the tool's inputSchema (topic is Required) and validate before dispatch."],"exampleFix":"// before\n{\"name\": \"research\", \"arguments\": {\"emit\": \"html\"}}\n// -> error: topic is required\n\n// after\n{\"name\": \"research\", \"arguments\": {\"topic\": \"rust 1.80 release\", \"emit\": \"html\"}}","handlingStrategy":"validation","validationCode":"// Validate before calling the research tool.\nfunc researchArgs(topic string, emit string, save bool) (map[string]any, error) {\n\tif topic == \"\" {\n\t\treturn nil, errors.New(\"topic is required: ask the user what to research\")\n\t}\n\treturn map[string]any{\"topic\": topic, \"emit\": emit, \"save\": save}, nil\n}","typeGuard":"func hasResearchTopic(args map[string]any) bool {\n\t_, ok := args[\"topic\"]\n\treturn ok\n}","tryCatchPattern":null,"preventionTips":["Always construct the arguments map with a literal \"topic\" key rather than building it dynamically from optional fields.","Fail fast in your own code when no topic exists — your message can be more actionable than the server's generic one.","Respect the tool schema: topic is marked Required, so client-side schema validation catches this before the round trip."],"tags":["go","mcp","validation","required-argument","arguments"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}