{"record":{"id":"1830f037f4e6eaff","repo":"googleapis/mcp-toolbox","slug":"error-in-user-agent-retrieval-s-1830f0","errorCode":null,"errorMessage":"error in User Agent retrieval: %s","messagePattern":"error in User Agent retrieval: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sources/serverlessspark/serverlessspark.go","lineNumber":70,"sourceCode":"\t}\n\treturn actual, nil\n}\n\ntype Config struct {\n\tName     string `yaml:\"name\" validate:\"required\"`\n\tType     string `yaml:\"type\" validate:\"required\"`\n\tProject  string `yaml:\"project\" validate:\"required\"`\n\tLocation string `yaml:\"location\" validate:\"required\"`\n}\n\nfunc (r Config) SourceConfigType() string {\n\treturn SourceType\n}\n\nfunc (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.Source, error) {\n\tua, err := util.UserAgentFromContext(ctx)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error in User Agent retrieval: %s\", err)\n\t}\n\tendpoint := fmt.Sprintf(\"%s-dataproc.googleapis.com:443\", r.Location)\n\tbatchClient, err := dataproc.NewBatchControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create dataproc batch client: %w\", err)\n\t}\n\tsessionTemplateClient, err := dataproc.NewSessionTemplateControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))\n\tif err != nil {\n\t\tbatchClient.Close()\n\t\treturn nil, fmt.Errorf(\"failed to create dataproc session template client: %w\", err)\n\t}\n\topsClient, err := longrunning.NewOperationsClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))\n\tif err != nil {\n\t\tbatchClient.Close()\n\t\tsessionTemplateClient.Close()\n\t\treturn nil, fmt.Errorf(\"failed to create longrunning client: %w\", err)\n\t}\n\tsessionClient, err := dataproc.NewSessionControllerClient(ctx, option.WithEndpoint(endpoint), option.WithUserAgent(ua))","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/sources/serverlessspark/serverlessspark.go#L52-L88","documentation":"Serverless Spark source Initialize first extracts a user agent string from the incoming context via util.UserAgentFromContext. If the context does not carry a valid user agent (missing or malformed), initialization fails before creating any Dataproc clients. This is a context/metadata plumbing error, not a network error.","triggerScenarios":"Config.Initialize runs util.UserAgentFromContext(ctx); the error branch fires when the context lacks the user agent header/metadata that the utility requires, or the metadata value fails the utility's parsing/format checks.","commonSituations":"Invoking the source programmatically with a bare context.Context instead of going through the toolbox server, which injects the user agent; constructing the source in unit tests without the expected metadata key; a client sending an empty or malformed User-Agent header.","solutions":["Create the source through the normal toolbox server request path so the user agent metadata is injected into the context.","If calling Initialize directly (tests/custom code), add the expected user agent to the context the way the server does (check util.UserAgentFromContext for the metadata key/format).","Ensure clients send a non-empty, well-formed User-Agent header.","Check the toolbox version for changes in the user agent contract between client and server."],"exampleFix":"// before (direct init in test)\nsrc, err := cfg.Initialize(ctx, tracer) // ctx has no user agent\n// after\nctx = metadata.AppendToOutgoingContext(ctx, \"user-agent\", \"opencode/1.0\")\nsrc, err := cfg.Initialize(ctx, tracer)","handlingStrategy":"try-catch","validationCode":"// Ensure the user agent is present in the outgoing context before source init\nua, err := util.UserAgentFromContext(ctx)\nif err != nil || ua == \"\" {\n    return fmt.Errorf(\"user agent missing from context: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"src, err := cfg.Initialize(ctx, tracer)\nif err != nil {\n    if strings.Contains(err.Error(), \"User Agent\") {\n        // re-init with a context carrying the user agent metadata\n        ctx = util.NewContextWithUserAgent(ctx, \"my-client/1.0\")\n        src, err = cfg.Initialize(ctx, tracer)\n    }\n    if err != nil { return err }\n}","preventionTips":["Instantiate sources via the toolbox server path, which injects user agent metadata.","When initializing directly in tests, build the context with the user agent the server uses.","Send a non-empty, well-formed User-Agent header from clients.","Check changelogs when upgrading the toolbox for user-agent contract changes."],"tags":["serverless-spark","dataproc","user-agent","context","go"],"backgroundTag":"missing-user-agent","analyzedSha":"8cc6e09de2ad7b8bffc77751799585a1401a48eb","analyzedAt":"2026-09-05T01:10:36.887Z","contentChangedAt":"2026-09-05T01:10:36.887Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}