gofr-dev/gofr · error

failed to marshal value to JSON: %w

Error message

failed to marshal value to JSON: %w

What it means

ToJSON marshals a Go value to a JSON string for use with KVStore.Set. This error wraps json.Marshal failures with 'failed to marshal value to JSON: %w' when the value contains types JSON cannot represent.

Source

Thrown at pkg/gofr/datasource/kv-store/dynamodb/dynamo.go:126

// UseMetrics sets the metrics for the Dynamo client which asserts the Metrics interface.
func (c *Client) UseMetrics(metrics any) {
	if m, ok := metrics.(Metrics); ok {
		c.metrics = m
	}
}

// UseTracer sets the tracer for Dynamo client.
func (c *Client) UseTracer(tracer any) {
	if tracer, ok := tracer.(trace.Tracer); ok {
		c.tracer = tracer
	}
}

// ToJSON converts a Go struct to JSON string for use with KVStore.Set.
func ToJSON(value any) (string, error) {
	jsonData, err := json.Marshal(value)
	if err != nil {
		return "", fmt.Errorf("failed to marshal value to JSON: %w", err)
	}

	return string(jsonData), nil
}

// FromJSON converts a JSON string to a Go struct for use with KVStore.Get.
func FromJSON(jsonData string, dest any) error {
	if err := json.Unmarshal([]byte(jsonData), dest); err != nil {
		return fmt.Errorf("failed to unmarshal JSON: %w", err)
	}

	return nil
}

func (c *Client) Get(ctx context.Context, key string) (string, error) {
	if !c.connected {
		return "", errClientNotConnected
	}

View on GitHub (pinned to 187eb24962)

Solutions

  1. Remove or tag unmarshalable fields (chan, func) with json:"-" so the marshaler skips them
  2. Convert NaN/Inf floats to valid numbers or omit them before calling ToJSON
  3. Call ToJSON first and log the wrapped %w cause to identify the offending field
  4. Pre-serialize in tests (Test_ToJSONError pattern) to catch bad shapes early

Example fix

// before
type Session struct { Done chan struct{} }
s, _ := ToJSON(Session{}) // error
// after
type Session struct { Done chan struct{} `json:"-"` }
s, err := ToJSON(Session{})
Defensive patterns

Strategy: validation

Validate before calling

func jsonSafe(v any) error {
    rv := reflect.ValueOf(v)
    for rv.Kind() == reflect.Ptr { rv = rv.Elem() }
    if rv.Kind() == reflect.Struct {
        for i := 0; i < rv.NumField(); i++ {
            switch rv.Field(i).Kind() {
            case reflect.Chan, reflect.Func, reflect.Complex64, reflect.Complex128:
                return fmt.Errorf("field %s not JSON-serializable", rv.Type().Field(i).Name)
            }
        }
    }
    return nil
}

Type guard

func isMarshalable(v any) bool { _, err := json.Marshal(v); return err == nil }

Try / catch

s, err := dynamodb.ToJSON(value)
if err != nil {
    var ue *json.UnsupportedTypeError
    if errors.As(err, &ue) { log.Printf("unsupported type: %v", ue.Value); return nil, err }
    return nil, err
}

Prevention

When it happens

Trigger: Calling ToJSON with a struct containing channels, functions, complex numbers, or NaN/Inf floats; passing a value with unmarshalable custom MarshalJSON that errors; cyclic data handled by marshal returning an error.

Common situations: Passing structs with func or chan fields (e.g. logger, connection handles) straight to Set, NaN from float math, time.Time in unusual layouts is fine but custom marshalers returning errors are not.

Related errors


AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01). Data as JSON: /api/errors/a7fce6f98f3ca79f. Report an issue: GitHub.