googleapis/mcp-toolbox · error

dry-run produced an empty execution plan

Error message

dry-run produced an empty execution plan

What it means

During a dry run, after an execution plan is obtained, RunCypher counts the plan's operators via buildPlanNode. If operatorCount is 0 the plan exists but is empty, so there is nothing meaningful to report — the tool rejects the dry-run result with this error. It guards against returning a useless empty plan structure to callers.

Source

Thrown at internal/sources/arcadedb/arcadedb.go:156

	}

	config := neo4j.ExecuteQueryWithDatabase(s.ArcadeDBDatabase())
	results, err := neo4j.ExecuteQuery[*neo4j.EagerResult](ctx, s.ArcadeDBDriver(), cypherStr, params,
		neo4j.EagerResultTransformer, config)
	if err != nil {
		return nil, fmt.Errorf("unable to execute query: %w", err)
	}

	if dryRun {
		summary := results.Summary
		plan := summary.Plan()
		if plan == nil {
			return nil, fmt.Errorf("dry-run produced no execution plan")
		}

		node, incomplete, operatorCount := buildPlanNode(plan)
		if operatorCount == 0 {
			return nil, fmt.Errorf("dry-run produced an empty execution plan")
		}

		execPlan := map[string]any{
			"queryType":     cf.Type.String(),
			"statementType": summary.QueryType(),
		}
		for k, v := range node {
			execPlan[k] = v
		}
		if incomplete {
			execPlan["plan_incomplete"] = true
			execPlan["warning"] = "Execution plan appears partial; server may not provide complete EXPLAIN details for this query/version."
		}
		return []map[string]any{execPlan}, nil
	}

	return formatRecords(results.Keys, results.Records), nil
}

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Run the query without dry-run to confirm it executes and returns results.
  2. Inspect the raw plan returned by EXPLAIN directly against the server to see its shape.
  3. Upgrade/align the server and driver versions so plan fields match what buildPlanNode expects.
  4. Use a different, more complex query if the statement trivially produces no operators.

Example fix

// before: degenerate plan from trivial statement
dryRun: true, query: "RETURN 1"
// after: dry-run a statement with real operators
dryRun: true, query: "MATCH (n:Person) RETURN n LIMIT 10"
Defensive patterns

Strategy: fallback

Try / catch

node, incomplete, operatorCount := buildPlanNode(plan)
if operatorCount == 0 {
    // plan is empty — fall back to executing the query or returning raw plan data
    return executeWithoutDryRun(ctx, cypher)
}

Prevention

When it happens

Trigger: Calling RunCypher with dryRun=true when the returned EXPLAIN plan has no operator nodes recognizable by buildPlanNode — an empty or degenerate plan from the server.

Common situations: Queries the backend plans as a no-op; protocol quirks producing plan objects with no children/arguments; compatibility mismatches where plan operator fields use unexpected keys.

Related errors


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