{"record":{"id":"f569b85cfc570bfa","repo":"jaegertracing/jaeger","slug":"tools-d-name-is-empty-or-whitespace","errorCode":null,"errorMessage":"tools[%d].name is empty or whitespace","messagePattern":"tools\\[(.+?)\\]\\.name is empty or whitespace","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/jaeger/internal/extension/jaegerquery/internal/jaegerai/translation.go","lineNumber":64,"sourceCode":"\treturn result\n}\n\n// validateContextualToolNames rejects requests carrying tools with empty\n// or whitespace-only names. Such names would prefix to \"ui_\" / \"ui_   \",\n// which the dispatcher's handleJaegerToolCall later rejects as\n// InvalidParams and which would land in both NewSessionRequest.Meta and\n// ContextualToolsStore as unusable entries. Returning a 400 from the\n// caller (handler.go) keeps both data structures clean and surfaces\n// frontend bugs immediately instead of allowing them to fail mid-turn\n// after a sidecar round-trip.\n//\n// The reported error names the first offending tool index so the\n// frontend developer can locate the broken declaration; it does not\n// reveal any user content from the rest of the request.\nfunc validateContextualToolNames(tools []aguitypes.Tool) error {\n\tfor i, tool := range tools {\n\t\tif strings.TrimSpace(tool.Name) == \"\" {\n\t\t\treturn fmt.Errorf(\"tools[%d].name is empty or whitespace\", i)\n\t\t}\n\t}\n\treturn nil\n}\n\n// prefixContextualTools returns a copy of the supplied tools with each\n// name prefixed by UIToolPrefix. The original slice is not mutated so the\n// caller can keep it for logging/inspection. Empty input returns nil so\n// callers can branch on the length to decide whether to attach Meta and\n// SetForSession at all.\n//\n// Callers must invoke validateContextualToolNames first to guarantee no\n// blank names slip through. This function does not re-validate so a stray\n// caller cannot accidentally bypass the boundary check.\nfunc prefixContextualTools(tools []aguitypes.Tool) []aguitypes.Tool {\n\tif len(tools) == 0 {\n\t\treturn nil\n\t}","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/jaegertracing/jaeger/blob/806f4447841ecdb60519f408b004a599d515f437/cmd/jaeger/internal/extension/jaegerquery/internal/jaegerai/translation.go#L46-L82","documentation":"validateContextualToolNames checks every contextual tool in an incoming AI request has a non-empty, non-whitespace name and reports the first offending index. It throws this so the frontend developer can locate the broken tool declaration, without exposing any user content from the rest of the request.","triggerScenarios":"POSTing a request to the jaegerquery AI HTTP endpoint whose tools array contains a Tool with Name == \"\" or only whitespace at index i.","commonSituations":"Frontend builds the tools array programmatically and a tool object failed to populate its name; schema drift between frontend and backend versions; JSON with a typo like \"nmae\".","solutions":["Fix the tool at the reported index in the request payload so its name is a non-empty trimmed string.","Add client-side validation that rejects tool entries with blank names before sending.","Confirm the frontend and jaegerquery versions agree on the request schema."],"exampleFix":"// before\n\"tools\": [{\"name\": \"\"}, {\"name\": \"search\"}]\n// after\n\"tools\": [{\"name\": \"get_trace\"}, {\"name\": \"search\"}]","handlingStrategy":"validation","validationCode":"func toolsValid(tools []aguitypes.Tool) error {\n    for i, t := range tools {\n        if strings.TrimSpace(t.Name) == \"\" {\n            return fmt.Errorf(\"tools[%d].name is empty or whitespace\", i)\n        }\n    }\n    return nil\n}\n// call before issuing the request\nif err := toolsValid(tools); err != nil { return err }","typeGuard":"func hasValidName(t aguitypes.Tool) bool {\n    return strings.TrimSpace(t.Name) != \"\"\n}","tryCatchPattern":"resp, err := http.Post(url, \"application/json\", body)\nif err != nil { return err }\nif resp.StatusCode == http.StatusBadRequest {\n    b, _ := io.ReadAll(resp.Body)\n    return fmt.Errorf(\"tool declaration rejected: %s\", b)\n}","preventionTips":["Validate tool declarations client-side before sending requests.","Generate tool arrays from typed constructors, never hand-written JSON with optional name fields.","Pin frontend/backend request schema versions together."],"tags":["validation","http-api","ai-tools"],"backgroundTag":"schema-validation-failed","analyzedSha":"806f4447841ecdb60519f408b004a599d515f437","analyzedAt":"2026-09-01T02:39:22.140Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}