googleapis/mcp-toolbox · error
operation finished with error but could not marshal error…
Error message
operation finished with error but could not marshal error object: %w
What it means
When a Cloud SQL operation reaches DONE status with a non-nil op.Error, the library attempts to json.Marshal op.Error to include its details in the returned error. If marshaling fails (extremely rare for API-generated OperationErrors, e.g. due to a client/version mismatch producing unmarshalable fields), this wrapper error is thrown instead of the operation's actual error. It indicates the operation failed but its error payload could not be serialized.
Solutions
- Upgrade google.golang.org/api (sqladmin package) to the latest version to fix any marshaling incompatibility
- Inspect op.Error fields directly via debugging/logging instead of relying on marshaling
- Log the operation name and fetch it with gcloud sql operations describe to see the real failure
- Check whether a proxy or modified client is corrupting API responses
Example fix
// before
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)
}
// after
if errorBytes, err = json.Marshal(op.Error); err != nil {
return nil, fmt.Errorf("operation finished with error (status=%s, errors=%v; marshal failed: %w)", op.Status, op.Error, err)
} Defensive patterns
Strategy: type-guard
Validate before calling
// Nothing meaningful can be validated pre-call; optionally sanity-check the client library version
import _ "google.golang.org/api/sqladmin/v1"
func checkClientUsable(op *sqladmin.Operation) error {
if op == nil {
return fmt.Errorf("nil operation")
}
if _, err := json.Marshal(op.Error); err != nil {
return fmt.Errorf("pre-check: op.Error is not marshalable: %w", err)
}
return nil
} Type guard
func operationErrorMarshalable(op *sqladmin.Operation) (string, bool) {
if op == nil || op.Error == nil {
return "", false
}
b, err := json.Marshal(op.Error)
if err != nil {
return fmt.Sprintf("%+v", op.Error), false
}
return string(b), true
} Try / catch
result, err := src.GetWaitForOperations(ctx, service, project, opName, tpl, delay)
if err != nil && strings.Contains(err.Error(), "could not marshal error object") {
// Fall back to raw API inspection
op, _ := service.Operations.Get(project, opName).Do()
if op != nil && op.Error != nil {
for _, e := range op.Error.Errors {
log.Printf("operation error: code=%s message=%s", e.Code, e.Message)
}
}
return
} Prevention
- Keep google.golang.org/api up to date so generated types marshal correctly
- Prefer reading structured fields (op.Error.Errors[].Code/Message) over JSON strings for error reporting
- Add a fallback in error handling that describes the operation via gcloud sql operations describe
When it happens
Trigger: service.Operations.Get returned an operation with Status == "DONE" and op.Error != nil, but json.Marshal(op.Error) returned an error — practically only when the sqladmin library's SqladminEmpty/OperationError types cannot serialize (unsupported types, custom marshaling failure).
Common situations: Almost never seen in practice; would require a corrupted or unexpected op.Error payload from the API, a Go google-cloud-go/sqladmin version incompatibility, or monkey-patched/defective JSON marshaling of the operation error type.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- could not marshal operation
- could not unmarshal operation
- operation finished with error
- error creating backup
- error creating instance
AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05).
Data as JSON: /api/errors/2f101e83c802c360.
Report an issue: GitHub.
Appendix: source
Thrown at internal/sources/cloudsqladmin/cloud_sql_admin.go:357
return resp, nil
}
func (s *Source) GetWaitForOperations(ctx context.Context, service *sqladmin.Service, project, operation, connectionMessageTemplate string, delay time.Duration) (any, error) {
logger, err := util.LoggerFromContext(ctx)
if err != nil {
return nil, err
}
op, err := service.Operations.Get(project, operation).Do()
if err != nil {
logger.DebugContext(ctx, fmt.Sprintf("error getting operation: %s, retrying in %v", err, delay))
} else {
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
}View on GitHub (pinned to 8cc6e09de2)