googleapis/mcp-toolbox · error

could not unmarshal operation: %w

Error message

could not unmarshal operation: %w

What it means

After successfully marshaling a DONE operation, the library unmarshals the bytes into map[string]any so generateCloudSQLConnectionMessage can extract connection details. If json.Unmarshal fails on bytes that were just marshaled from a sqladmin.Operation, this error is thrown. This should be unreachable with valid operation data and signals a corrupted payload or a marshaling/serialization mismatch.

Source

Thrown at internal/sources/cloudsqladmin/cloud_sql_admin.go:370

		if op.Status == "DONE" {
			if op.Error != nil {
				var errorBytes []byte
				errorBytes, err = json.Marshal(op.Error)
				if err != nil {
					return nil, fmt.Errorf("operation finished with error but could not marshal error object: %w", err)
				}
				return nil, fmt.Errorf("operation finished with error: %s", string(errorBytes))
			}

			var opBytes []byte
			opBytes, err = op.MarshalJSON()
			if err != nil {
				return nil, fmt.Errorf("could not marshal operation: %w", err)
			}

			var data map[string]any
			if err := json.Unmarshal(opBytes, &data); err != nil {
				return nil, fmt.Errorf("could not unmarshal operation: %w", err)
			}

			if msg, ok := generateCloudSQLConnectionMessage(ctx, s, logger, data, connectionMessageTemplate); ok {
				return msg, nil
			}
			return string(opBytes), nil
		}
		logger.DebugContext(ctx, fmt.Sprintf("operation not complete, retrying in %v", delay))
	}
	return nil, nil
}

func (s *Source) InsertBackupRun(ctx context.Context, project, instance, location, backupDescription, accessToken string) (any, error) {
	backupRun := &sqladmin.BackupRun{}
	if location != "" {
		backupRun.Location = location
	}
	if backupDescription != "" {

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Upgrade google.golang.org/api to the latest version
  2. Log opBytes content on failure to inspect what was produced and why it cannot unmarshal
  3. Bypass the map conversion: pass opBytes or a typed struct to the connection-message generator instead
  4. Verify no proxy/middleware is transforming the API response payload

Example fix

// before
var data map[string]any
if err := json.Unmarshal(opBytes, &data); err != nil {
    return nil, fmt.Errorf("could not unmarshal operation: %w", err)
}
// after
var data map[string]any
if err := json.Unmarshal(opBytes, &data); err != nil {
    return nil, fmt.Errorf("could not unmarshal operation %s: %w (raw: %s)", operation, err, string(opBytes))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the marshaled operation bytes decode into a map before downstream use
func operationDecodable(opBytes []byte) error {
    var probe map[string]any
    if err := json.Unmarshal(opBytes, &probe); err != nil {
        return fmt.Errorf("operation bytes not decodable: %w", err)
    }
    return nil
}

Type guard

func decodeOperation(opBytes []byte) (map[string]any, bool) {
    var data map[string]any
    if err := json.Unmarshal(opBytes, &data); err != nil {
        return nil, false
    }
    return data, true
}

Try / catch

result, err := src.GetWaitForOperations(ctx, service, project, opName, tpl, delay)
if err != nil && strings.Contains(err.Error(), "could not unmarshal operation") {
    // Graceful fallback: return the raw operation JSON via REST
    resp, rerr := service.Operations.Get(project, opName).Do()
    if rerr == nil {
        raw, _ := json.Marshal(resp)
        fmt.Println(string(raw))
    }
    return
}

Prevention

When it happens

Trigger: op.MarshalJSON() succeeded but produced bytes that json.Unmarshal into map[string]any rejects — e.g. malformed JSON from a custom/broken MarshalJSON implementation or a struct containing a function/invalid field rendered incorrectly.

Common situations: Essentially only seen with a broken or mismatched google.golang.org/api version, patched client code, or intercepting proxies that corrupt the operation JSON before it reaches local marshaling.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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