googleapis/mcp-toolbox · error

failed to marshal operation to JSON: %w

Error message

failed to marshal operation to JSON: %w

What it means

GetOperation fetches a Dataplex long-running operation and serializes it with protojson to return JSON to the caller. If protojson cannot marshal the returned *longrunningpb.Operation (nil pointer or invalid proto state), the error is wrapped as 'failed to marshal operation to JSON'. This is an internal serialization failure, not an API error.

Source

Thrown at internal/sources/dataplex/dataplex.go:922

	return s.DataScanClient.GetDataScan(ctx, req)
}

func (s *Source) GetOperation(ctx context.Context, opName string) (map[string]any, error) {
	if !operationNameRegex.MatchString(opName) {
		return nil, fmt.Errorf("invalid operation name format: %q (expected projects/*/locations/*/operations/*)", opName)
	}

	req := &longrunningpb.GetOperationRequest{
		Name: opName,
	}
	op, err := s.DataScanClient.LROClient.GetOperation(ctx, req)
	if err != nil {
		return nil, err
	}

	bytes, err := protojson.Marshal(op)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal operation to JSON: %w", err)
	}

	var opData map[string]any
	if err := json.Unmarshal(bytes, &opData); err != nil {
		return nil, fmt.Errorf("failed to unmarshal operation JSON to map: %w", err)
	}

	return opData, nil
}

func (s *Source) GetJobStatus(ctx context.Context, location, scanID, jobID string) (*dataplexpb.DataScanJob, error) {
	// If jobID is provided, fetch that specific job directly!
	if jobID != "" {
		name := fmt.Sprintf("projects/%s/locations/%s/dataScans/%s/jobs/%s", s.ProjectID(), location, scanID, jobID)
		req := &dataplexpb.GetDataScanJobRequest{
			Name: name,
		}
		return s.DataScanClient.GetDataScanJob(ctx, req)

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Check that the operation name passed to GetOperation exists and the client returned a non-nil operation
  2. Verify the google.golang.org/genproto dataplex/longrunning proto versions are consistent (go mod tidy / go get -u)
  3. If using a mock client, ensure the stub returns a valid *longrunningpb.Operation
  4. Log the underlying wrapped error (%w) to see the exact protojson failure

Example fix

// before
op, err := src.GetOperation(ctx, "")
// after
if opName == "" {
    return errors.New("operation name is required")
}
op, err := src.GetOperation(ctx, opName)
Defensive patterns

Strategy: try-catch

Validate before calling

if op == nil || op.GetName() == "" { return errors.New("no operation returned") }

Type guard

op, ok := resp.(*longrunningpb.Operation); if !ok || op == nil { ... }

Try / catch

op, err := src.GetOperation(ctx, name)
if err != nil {
	var uerr interface{ Unwrap() error }
	if errors.As(err, &uerr) { log.Printf("underlying: %v", uerr) }
	return fmt.Errorf("get operation failed: %w", err)
}

Prevention

When it happens

Trigger: Calling GetOperation when the Dataplex client returns an operation value that protojson cannot encode — typically a nil operation pointer or a corrupt/invalid proto message.

Common situations: Operation not found paths returning nil without error from a stub; passing an operation from a mismatched proto package version; mocking the DataScanClient with an invalid message.

Related errors


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