{"record":{"id":"1795590642027685","repo":"googleapis/mcp-toolbox","slug":"cannot-provide-both-mainjarfile-and-mainclass","errorCode":null,"errorMessage":"cannot provide both mainJarFile and mainClass","messagePattern":"cannot provide both mainJarFile and mainClass","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go","lineNumber":85,"sourceCode":"\t\tparameters.NewStringParameter(\"mainJarFile\", \"Optional. The gs:// URI of the jar file that contains the main class. Exactly one of mainJarFile or mainClass must be specified.\", parameters.WithStringRequired(false)),\n\t\tparameters.NewStringParameter(\"mainClass\", \"Optional. The name of the driver's main class. Exactly one of mainJarFile or mainClass must be specified.\", parameters.WithStringRequired(false)),\n\t\tparameters.NewArrayParameter(\"jarFiles\", \"Optional. A list of gs:// URIs of jar files to add to the CLASSPATHs of the Spark driver and tasks.\", parameters.NewStringParameter(\"jarFile\", \"A jar file URI.\"), parameters.WithArrayRequired(false)),\n\t\tparameters.NewArrayParameter(\"args\", \"Optional. A list of arguments passed to the driver.\", parameters.NewStringParameter(\"arg\", \"An argument.\"), parameters.WithArrayRequired(false)),\n\t\tparameters.NewStringParameter(\"version\", \"Optional. The Serverless runtime version to execute with.\", parameters.WithStringRequired(false)),\n\t}\n}\n\nfunc (b *SparkBatchBuilder) BuildBatch(params parameters.ParamValues) (*dataproc.Batch, error) {\n\tparamMap := params.AsMap()\n\n\tmainJar, _ := paramMap[\"mainJarFile\"].(string)\n\tmainClass, _ := paramMap[\"mainClass\"].(string)\n\n\tif mainJar == \"\" && mainClass == \"\" {\n\t\treturn nil, fmt.Errorf(\"must provide either mainJarFile or mainClass\")\n\t}\n\tif mainJar != \"\" && mainClass != \"\" {\n\t\treturn nil, fmt.Errorf(\"cannot provide both mainJarFile and mainClass\")\n\t}\n\n\tsparkBatch := &dataproc.SparkBatch{}\n\tif mainJar != \"\" {\n\t\tsparkBatch.Driver = &dataproc.SparkBatch_MainJarFileUri{MainJarFileUri: mainJar}\n\t} else {\n\t\tsparkBatch.Driver = &dataproc.SparkBatch_MainClass{MainClass: mainClass}\n\t}\n\n\tif jarFileUris, ok := paramMap[\"jarFiles\"].([]any); ok {\n\t\tfor _, uri := range jarFileUris {\n\t\t\tsparkBatch.JarFileUris = append(sparkBatch.JarFileUris, fmt.Sprintf(\"%v\", uri))\n\t\t}\n\t} else if mainClass != \"\" {\n\t\treturn nil, fmt.Errorf(\"jarFiles is required when mainClass is provided\")\n\t}\n\n\tif args, ok := paramMap[\"args\"].([]any); ok {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go#L67-L103","documentation":"BuildBatch enforces mutual exclusivity of the two entrypoint styles: a Dataproc SparkBatch driver must be set either via MainJarFileUri or MainClass, never both. When both mainJarFile and mainClass are non-empty, this error rejects the conflicting request before any API call is made.","triggerScenarios":"Invoking create-spark-batch with both 'mainJarFile' and 'mainClass' set to non-empty strings in the params map.","commonSituations":"Agents or templates that always populate defaults for both parameters; users copying examples that include both fields; combining a config-level default mainClass with a request-level mainJarFile.","solutions":["Remove either mainJarFile or mainClass from the parameters, keeping exactly one","If a default is injected by a template/config, delete the redundant field from the tool call","Re-issue the invoke with the single remaining entrypoint"],"exampleFix":"// before\nparams := map[string]any{\"mainJarFile\": \"gs://b/app.jar\", \"mainClass\": \"com.example.Main\"}\n// after\nparams := map[string]any{\"mainJarFile\": \"gs://b/app.jar\"}","handlingStrategy":"validation","validationCode":"jar, _ := params[\"mainJarFile\"].(string)\ncls, _ := params[\"mainClass\"].(string)\nif jar != \"\" && cls != \"\" {\n    return errors.New(\"drop one: mainJarFile and mainClass are mutually exclusive\")\n}","typeGuard":null,"tryCatchPattern":"res, tbErr := tool.Invoke(ctx, src, paramValues, token)\nif tbErr != nil && strings.Contains(tbErr.Error(), \"cannot provide both mainJarFile and mainClass\") {\n    // strip mainClass (or mainJarFile) and re-invoke\n}","preventionTips":["Prefer mainJarFile for fat JARs; use mainClass+jarFiles only for classpath-style launches","Strip template-injected defaults before adding your own entrypoint param","Unit-test param-building code for mutual exclusivity"],"tags":["validation","parameters","dataproc","serverlessspark"],"backgroundTag":"conflicting-parameters","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"}