{"record":{"id":"5fda7764ae3153dc","repo":"googleapis/mcp-toolbox","slug":"must-provide-either-mainjarfile-or-mainclass","errorCode":null,"errorMessage":"must provide either mainJarFile or mainClass","messagePattern":"must provide either mainJarFile or mainClass","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go","lineNumber":82,"sourceCode":"\nfunc (b *SparkBatchBuilder) Parameters() parameters.Parameters {\n\treturn parameters.Parameters{\n\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\")","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/googleapis/mcp-toolbox/blob/8cc6e09de2ad7b8bffc77751799585a1401a48eb/internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go#L64-L100","documentation":"BuildBatch assembles a Dataproc SparkBatch from tool parameters and requires exactly one of mainJarFile or mainClass to identify the application entrypoint. If neither parameter is supplied (both resolve to empty strings), the batch cannot be constructed and this validation error is returned to the caller.","triggerScenarios":"Invoking the serverless-spark-create-spark-batch tool with a params map lacking both 'mainJarFile' and 'mainClass' keys, or supplying them as empty strings / non-string values that fail the type assertion to string.","commonSituations":"LLM/agent omitting optional-looking parameters in generated tool calls; clients sending only jarFiles/args without an entrypoint; params passed as non-string types (e.g. numbers) silently becoming empty strings.","solutions":["Include either mainJarFile (URI to the driver JAR) or mainClass (fully-qualified class name) in the tool call parameters","If a non-entrypoint param set is intended, verify parameter names are spelled exactly 'mainJarFile'/'mainClass'","Ensure the values are plain JSON strings, not null or nested objects"],"exampleFix":"// before\nparams := map[string]any{\"jarFiles\": []any{\"gs://bucket/lib.jar\"}}\n// after\nparams := map[string]any{\"mainClass\": \"com.example.Main\", \"jarFiles\": []any{\"gs://bucket/lib.jar\"}}","handlingStrategy":"validation","validationCode":"jar, _ := params[\"mainJarFile\"].(string)\ncls, _ := params[\"mainClass\"].(string)\nif jar == \"\" && cls == \"\" {\n    return errors.New(\"supply exactly one of mainJarFile or mainClass\")\n}","typeGuard":null,"tryCatchPattern":"res, tbErr := tool.Invoke(ctx, src, paramValues, token)\nif tbErr != nil && strings.Contains(tbErr.Error(), \"must provide either mainJarFile or mainClass\") {\n    // prompt caller/LLM to add an entrypoint parameter and retry once\n}","preventionTips":["Always send exactly one of mainJarFile/mainClass in tool calls","Ensure values are JSON strings, not null or non-string types (empty strings count as missing)","For LLM agents, document the either-or constraint in the tool description"],"tags":["validation","parameters","dataproc","serverlessspark"],"backgroundTag":"missing-required-argument","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"}