Handling String to int64 Conversion in Go JSON Unmarshalling

Dec 03, 2025 · Programming · 11 views · 7.8

Keywords: Go programming | JSON parsing | type conversion | string handling | cross-language data exchange

Abstract: This article addresses the common issue in Go where int64 fields serialized as strings from JavaScript cause unmarshalling errors. Focusing on the "cannot unmarshal string into Go value of type int64" error, it presents the solution using the ",string" option in JSON struct tags. The discussion covers practical scenarios, implementation details, and best practices for robust cross-language data exchange between Go backends and JavaScript frontends.

Problem Context and Scenario Analysis

In modern web development, data exchange between Go backends and JavaScript frontends typically occurs through JSON format. However, due to JavaScript's limitations in handling numeric types (particularly for values exceeding 32-bit integer range), developers frequently encounter data type mismatch issues. A common scenario involves int64 fields from Go structs being serialized as strings in JavaScript, causing parsing failures in the Go backend.

Error Manifestation and Root Cause

Consider the following Go struct definition:

type tySurvey struct {
    Id     int64            `json:"id,omitempty"`
    Name   string           `json:"name,omitempty"`
}

When this struct is serialized via json.Marshal and sent to the frontend, JavaScript libraries like jQuery may process the data and treat the id field as a string. For instance, originally sent data might be {"id":1}, but after JavaScript processing, the received data becomes {"id":"1"}. When attempting to unmarshal this data using json.Unmarshal, Go returns the error:

json: cannot unmarshal string into Go value of type int64

The core issue is that the JSON parser expects the id field to be a numeric type but receives a string instead, resulting in type mismatch.

Solution: The ",string" Tag Option

Go's encoding/json package provides an elegant solution through the ,string option in struct tags. The modified struct definition becomes:

type tySurvey struct {
    Id     int64            `json:"id,string,omitempty"`
    Name   string           `json:"name,omitempty"`
}

This tag option instructs the JSON parser to serialize the Id field as a string during marshalling and allows parsing from string values to int64 during unmarshalling. This bidirectional conversion mechanism effectively resolves data type mismatches between JavaScript and Go.

Implementation Mechanism and Working Principle

The ,string tag option leverages Go's reflection mechanism and the JSON parser's type conversion logic. When the parser encounters a field with this tag:

  1. During marshalling, it calls strconv.FormatInt to convert int64 values to strings
  2. During unmarshalling, it reads string values and uses strconv.ParseInt for conversion to int64
  3. The entire conversion process is transparent to developers, eliminating the need for manual conversion code

This approach is particularly valuable for handling large integers, as JavaScript's Number type can only safely represent integers between -(2^53-1) and 2^53-1, while Go's int64 supports the full 64-bit integer range.

Usage Considerations and Best Practices

When using the ,string tag option, several important considerations apply:

  1. Empty String Handling: The omitempty tag does not apply to empty strings, as it only affects encoding (marshalling)
  2. Error Handling: If strings contain non-numeric characters, the parser returns errors that require proper handling in code
  3. Performance Implications: Additional type conversions introduce minor performance overhead, typically negligible in most applications
  4. Compatibility: This solution maintains full compatibility with standard JSON specifications and doesn't affect other clients' data parsing

Complete Example Implementation

The following complete example demonstrates practical application of this solution:

package main

import (
    "encoding/json"
    "fmt"
    "log"
)

type Survey struct {
    ID   int64  `json:"id,string,omitempty"`
    Name string `json:"name,omitempty"`
}

func main() {
    // Simulate JSON data received from JavaScript
    jsData := `{"id":"1234567890123456789","name":"Test Survey"}`
    
    var survey Survey
    err := json.Unmarshal([]byte(jsData), &survey)
    if err != nil {
        log.Fatal("Unmarshal error:", err)
    }
    
    fmt.Printf("Parsed survey: ID=%d, Name=%s\n", survey.ID, survey.Name)
    
    // Marshal back to JSON
    output, err := json.Marshal(survey)
    if err != nil {
        log.Fatal("Marshal error:", err)
    }
    
    fmt.Printf("Serialized JSON: %s\n", string(output))
}

Alternative Approaches Comparison

Beyond the ,string tag option, developers might consider these alternatives:

  1. Custom UnmarshalJSON Method: Implement custom UnmarshalJSON methods for structs to provide more flexible type conversion logic
  2. Using interface{} Type: Declare fields as interface{} types and perform type assertions and conversions in code
  3. Frontend Data Preprocessing: Ensure numeric fields remain as numbers in JavaScript before transmission

However, the ,string tag option remains the preferred approach due to its simplicity, maintainability, and standard library support.

Conclusion

When handling JSON data in Go where int64 fields need to be transmitted as strings in JavaScript environments, using the json:"fieldname,string,omitempty" tag represents best practice. This solution offers code simplicity while being fully integrated into the standard library without requiring third-party dependencies. By understanding its working principles and considerations, developers can create robust, maintainable cross-language data exchange code that effectively prevents common errors like "cannot unmarshal string into Go value of type int64".

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.