googleapis/mcp-toolbox · error

failed to unmarshal operation JSON to map: %w

Error message

failed to unmarshal operation JSON to map: %w

What it means

After GetOperation successfully marshals the operation with protojson, it decodes the JSON bytes into a map[string]any for the caller. If the JSON produced cannot be unmarshaled into a map (corrupt or non-object payload), this wrapped error is returned. Practically unreachable with valid protojson output, but it hardens the conversion path.

Source

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

		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)
	}

	// Fallback to listing and returning the latest job (PageSize: 1)
	parent := fmt.Sprintf("projects/%s/locations/%s/dataScans/%s", s.ProjectID(), location, scanID)
	req := &dataplexpb.ListDataScanJobsRequest{

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the wrapped error from json.Unmarshal for the exact cause
  2. Re-run with a stock protojson.Marshal to confirm output is a JSON object
  3. Ensure no middleware rewrites the marshaled bytes
  4. Update the dataplex client/proto dependencies if a known bug applies
Defensive patterns

Strategy: try-catch

Validate before calling

if len(bytes) == 0 || bytes[0] != '{' { return errors.New("operation payload is not a JSON object") }

Try / catch

opData, err := src.GetOperation(ctx, name)
if err != nil {
	if strings.Contains(err.Error(), "unmarshal operation JSON") {
		// fall back to raw operation proto inspection
	}
	return err
}

Prevention

When it happens

Trigger: Calling GetOperation when the intermediate JSON bytes from protojson.Marshal are not a valid JSON object (only possible with corrupted output or replaced marshaler behavior).

Common situations: Custom/patched protojson behavior; intermediary mutation of bytes; extremely rare in production — mostly seen in mocked or instrumented clients.

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/b5ceee072c7a15d6. Report an issue: GitHub.