googleapis/mcp-toolbox · error

cannot provide both mainJarFile and mainClass

Error message

cannot provide both mainJarFile and mainClass

What it means

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.

Source

Thrown at internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go:85

		parameters.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)),
		parameters.NewStringParameter("mainClass", "Optional. The name of the driver's main class. Exactly one of mainJarFile or mainClass must be specified.", parameters.WithStringRequired(false)),
		parameters.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)),
		parameters.NewArrayParameter("args", "Optional. A list of arguments passed to the driver.", parameters.NewStringParameter("arg", "An argument."), parameters.WithArrayRequired(false)),
		parameters.NewStringParameter("version", "Optional. The Serverless runtime version to execute with.", parameters.WithStringRequired(false)),
	}
}

func (b *SparkBatchBuilder) BuildBatch(params parameters.ParamValues) (*dataproc.Batch, error) {
	paramMap := params.AsMap()

	mainJar, _ := paramMap["mainJarFile"].(string)
	mainClass, _ := paramMap["mainClass"].(string)

	if mainJar == "" && mainClass == "" {
		return nil, fmt.Errorf("must provide either mainJarFile or mainClass")
	}
	if mainJar != "" && mainClass != "" {
		return nil, fmt.Errorf("cannot provide both mainJarFile and mainClass")
	}

	sparkBatch := &dataproc.SparkBatch{}
	if mainJar != "" {
		sparkBatch.Driver = &dataproc.SparkBatch_MainJarFileUri{MainJarFileUri: mainJar}
	} else {
		sparkBatch.Driver = &dataproc.SparkBatch_MainClass{MainClass: mainClass}
	}

	if jarFileUris, ok := paramMap["jarFiles"].([]any); ok {
		for _, uri := range jarFileUris {
			sparkBatch.JarFileUris = append(sparkBatch.JarFileUris, fmt.Sprintf("%v", uri))
		}
	} else if mainClass != "" {
		return nil, fmt.Errorf("jarFiles is required when mainClass is provided")
	}

	if args, ok := paramMap["args"].([]any); ok {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Remove either mainJarFile or mainClass from the parameters, keeping exactly one
  2. If a default is injected by a template/config, delete the redundant field from the tool call
  3. Re-issue the invoke with the single remaining entrypoint

Example fix

// before
params := map[string]any{"mainJarFile": "gs://b/app.jar", "mainClass": "com.example.Main"}
// after
params := map[string]any{"mainJarFile": "gs://b/app.jar"}
Defensive patterns

Strategy: validation

Validate before calling

jar, _ := params["mainJarFile"].(string)
cls, _ := params["mainClass"].(string)
if jar != "" && cls != "" {
    return errors.New("drop one: mainJarFile and mainClass are mutually exclusive")
}

Try / catch

res, tbErr := tool.Invoke(ctx, src, paramValues, token)
if tbErr != nil && strings.Contains(tbErr.Error(), "cannot provide both mainJarFile and mainClass") {
    // strip mainClass (or mainJarFile) and re-invoke
}

Prevention

When it happens

Trigger: Invoking create-spark-batch with both 'mainJarFile' and 'mainClass' set to non-empty strings in the params map.

Common situations: 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.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/1795590642027685. Report an issue: GitHub.