googleapis/mcp-toolbox · error
jarFiles is required when mainClass is provided
Error message
jarFiles is required when mainClass is provided
What it means
A Spark batch that runs via mainClass needs the class on the driver classpath, which comes from jarFileUris. BuildBatch enforces that when mainClass is provided and no 'jarFiles' array parameter is present, the request is invalid — the jar containing the class must be supplied. Note the check triggers when jarFiles is absent entirely (type assertion to []any fails), not when it is merely empty.
Source
Thrown at internal/tools/serverlessspark/serverlesssparkcreatesparkbatch/serverlesssparkcreatesparkbatch.go:100
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 {
for _, arg := range args {
sparkBatch.Args = append(sparkBatch.Args, fmt.Sprintf("%v", arg))
}
}
return &dataproc.Batch{
BatchConfig: &dataproc.Batch_SparkBatch{
SparkBatch: sparkBatch,
},
}, nil
}
View on GitHub (pinned to 8cc6e09de2)
Solutions
- Add a 'jarFiles' array parameter containing the URIs of JARs that provide the main class
- If jarFiles was passed as a string, convert it to a JSON array (e.g. ["gs://bucket/app.jar"])
- Alternatively, use mainJarFile instead of mainClass+jarFiles to point directly at the application JAR
Example fix
// before
params := map[string]any{"mainClass": "com.example.Main", "jarFiles": "gs://b/app.jar"}
// after
params := map[string]any{"mainClass": "com.example.Main", "jarFiles": []any{"gs://b/app.jar"}} Defensive patterns
Strategy: validation
Validate before calling
cls, _ := params["mainClass"].(string)
jars, ok := params["jarFiles"].([]any)
if cls != "" && (!ok || len(jars) == 0) {
return errors.New("jarFiles array required when mainClass is set")
} Type guard
func hasJarFiles(params map[string]any) bool {
_, ok := params["jarFiles"].([]any)
return ok
} Try / catch
res, tbErr := tool.Invoke(ctx, src, paramValues, token)
if tbErr != nil && strings.Contains(tbErr.Error(), "jarFiles is required when mainClass is provided") {
// add jarFiles: ["gs://..."] and re-invoke
} Prevention
- Always pass jarFiles as a JSON array, never a single string (array type assertion fails otherwise)
- When using mainClass, ship the class inside a JAR uploaded to GCS and list its URI
- Prefer mainJarFile when the app is a single self-contained JAR to sidestep this rule
When it happens
Trigger: Invoking create-spark-batch with mainClass set but with no 'jarFiles' parameter at all (key missing or not a []any array, e.g. a single string instead of a list).
Common situations: Users assuming the main class is already bundled in the cluster image; passing jarFiles as a comma-separated string rather than an array so the []any assertion fails; agents generating mainClass-only calls.
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
- must provide either mainJarFile or mainClass
- cannot provide both mainJarFile and mainClass
- 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/29287a0476ac83bb.
Report an issue: GitHub.