googleapis/mcp-toolbox · error

operation finished with error

Error message

operation finished with error: %s

What it means

This error is returned by GetOperations when a polled AlloyDB long-running operation has completed unsuccessfully: op.Done is true and op.Error is non-nil. The Google Rpc.Status object (HTTP status code and error message from the failed operation) is JSON-marshaled and embedded in this message, so the full failure reason is in the error text. It represents the authoritative failure of a create/delete/patch operation, not a client-side problem.

Solutions

  1. Parse the JSON payload in the message (fields code and message) to read the API's failure reason
  2. If the code indicates quota (e.g., 8/RESOURCE_EXHAUSTED or 429), check AlloyDB quotas in the Cloud Console and request an increase
  3. If permissions-related, verify the caller's IAM roles include roles/alloydb.admin before re-running the operation
  4. Fix the underlying configuration (machine type, network, region) and resubmit the create/update request
  5. Check Cloud Logging for the operation's detailed server-side logs for root cause

Example fix

// before
if op.Error != nil {
    errorBytes, _ := json.Marshal(op.Error)
    return nil, fmt.Errorf("operation finished with error: %s", string(errorBytes))
}
// after
if op.Error != nil {
    var rpcStatus struct {
        Code    int    `json:"code"`
        Message string `json:"message"`
    }
    if b, err := json.Marshal(op.Error); err == nil && json.Unmarshal(b, &rpcStatus) == nil {
        return nil, fmt.Errorf("operation failed (gRPC code %d): %s", rpcStatus.Code, rpcStatus.Message)
    }
    errorBytes, _ := json.Marshal(op.Error)
    return nil, fmt.Errorf("operation finished with error: %s", string(errorBytes))
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go: pre-flight checks before starting/polling an operation
if err := checkQuotaAndBilling(project); err != nil {
    return fmt.Errorf("preflight failed: %w", err)
}
// ensure config (machine type, region, network) is valid before submitting

Type guard

func ParseOperationFailure(err error) (grpcCode int, message string, ok bool) {
    const prefix = "operation finished with error: "
    msg := err.Error()
    i := strings.Index(msg, prefix)
    if i < 0 {
        return 0, "", false
    }
    var st struct {
        Code    int    `json:"code"`
        Message string `json:"message"`
    }
    if json.Unmarshal([]byte(msg[i+len(prefix):]), &st) != nil {
        return 0, "", false
    }
    return st.Code, st.Message, true
}

Try / catch

_, err := s.GetOperations(ctx, project, location, opName, tmpl, pollDelay, accessToken)
if err != nil {
    if code, msg, ok := ParseOperationFailure(err); ok {
        switch code {
        case 8: // RESOURCE_EXHAUSTED
            return fmt.Errorf("quota exceeded: %s — request quota increase", msg)
        case 7: // PERMISSION_DENIED
            return fmt.Errorf("IAM permission missing: %s", msg)
        default:
            return fmt.Errorf("operation failed: %s", msg)
        }
    }
    return err
}

Prevention

When it happens

Trigger: Polling an operation via Projects.Locations.Operations.Get whose target action failed server-side — e.g., instance creation rejected due to quota exhaustion, invalid configuration, permission denial, or resource conflicts — and the API returned Done=true with an Error status.

Common situations: Exceeded AlloyDB quota or regional capacity, invalid instance settings (machine type, network), permission revoked between request start and completion, project billing issues, and conflicts like a duplicate resource created concurrently.

Related errors


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

Appendix: source

Thrown at internal/sources/alloydbadmin/alloydbadmin.go:351

	service, err := s.getService(ctx, accessToken)
	if err != nil {
		return nil, err
	}

	name := fmt.Sprintf("projects/%s/locations/%s/operations/%s", project, location, operation)

	op, err := service.Projects.Locations.Operations.Get(name).Do()
	if err != nil {
		logger.DebugContext(ctx, fmt.Sprintf("error getting operation: %s, retrying in %v\n", err, delay))
	} else {
		if op.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)
			}

			if op.Response != nil {
				var responseData map[string]any
				if err := json.Unmarshal(op.Response, &responseData); err == nil && responseData != nil {
					if msg, ok := generateAlloyDBConnectionMessage(responseData, connectionMessageTemplate); ok {
						return msg, nil
					}
				}
			}

			var result any

View on GitHub (pinned to 8cc6e09de2)