googleapis/mcp-toolbox · error
must provide either mainJarFile or mainClass
Error message
must provide either mainJarFile or mainClass
What it means
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.
Source
Thrown at internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go:82
func (b *SparkBatchBuilder) Parameters() parameters.Parameters {
return parameters.Parameters{
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")View on GitHub (pinned to 8cc6e09de2)
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
Example fix
// before
params := map[string]any{"jarFiles": []any{"gs://bucket/lib.jar"}}
// after
params := map[string]any{"mainClass": "com.example.Main", "jarFiles": []any{"gs://bucket/lib.jar"}} Defensive patterns
Strategy: validation
Validate before calling
jar, _ := params["mainJarFile"].(string)
cls, _ := params["mainClass"].(string)
if jar == "" && cls == "" {
return errors.New("supply exactly one of mainJarFile or mainClass")
} Try / catch
res, tbErr := tool.Invoke(ctx, src, paramValues, token)
if tbErr != nil && strings.Contains(tbErr.Error(), "must provide either mainJarFile or mainClass") {
// prompt caller/LLM to add an entrypoint parameter and retry once
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- cannot provide both mainJarFile and mainClass
- jarFiles is required when mainClass is provided
- tool %q config error: parameter %q (index %d) references '%q
- tool %q config error: parameter %q cannot copy value from it
- invalid jobStateMatcher: %s. Supported values: ALL, ACTIVE,
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/5fda7764ae3153dc.
Report an issue: GitHub.