Avoid These 5 Common Go Standard Library Pitfalls and Write Safer Code

This article examines frequent mistakes developers make when using Go’s standard library—such as misusing time.Duration, causing memory leaks with time.After, JSON serialization quirks, improper SQL handling, and HTTP response errors—providing concrete code examples and best‑practice solutions to write more reliable, efficient Go programs.

FunTester
FunTester
FunTester
Avoid These 5 Common Go Standard Library Pitfalls and Write Safer Code

1. Misusing time.Duration

Many developers mistakenly pass an integer directly to time.Sleep, assuming the value is in seconds. In reality, time.Duration is expressed in nanoseconds, so time.Sleep(1000) only pauses for one microsecond, leading to unexpected behavior.

package main

import (
    "fmt"
    "time"
)

func main() {
    // Wrong: passing an integer directly
    time.Sleep(1000) // actually 1000 nanoseconds, not 1 second
    fmt.Println("Sleep completed")
}

Best practice: Use explicit time units so the intention is clear.

package main

import (
    "fmt"
    "time"
)

func main() {
    time.Sleep(1 * time.Second) // clear intent
    fmt.Println("FunTester sleep completed")
}

2. Memory leak caused by time.After

Calling time.After inside a loop creates a new timer on each iteration. The timers are never released, which can gradually increase memory usage and eventually exhaust resources.

package main

import (
    "fmt"
    "time"
)

func main() {
    for i := 0; i < 1000; i++ {
        <-time.After(1 * time.Second) // creates a new timer each loop
        fmt.Println("FunTester scheduled task")
    }
}

Best practice: Use time.NewTimer and reuse the timer, stopping it when done.

package main

import (
    "fmt"
    "time"
)

func main() {
    timer := time.NewTimer(1 * time.Second)
    defer timer.Stop() // ensure the timer is released
    for i := 0; i < 1000; i++ {
        <-timer.C
        fmt.Println("FunTester scheduled task")
        timer.Reset(1 * time.Second) // reuse the timer
    }
}

3. Common JSON handling pitfalls

(1) Unexpected behavior from embedded types

Embedding time.Time directly in a struct overrides the default JSON marshaling, producing an unexpected output.

type Event struct {
    Name string
    time.Time // embedded time.Time changes JSON behavior
}

Best practice: Define explicit JSON field tags and avoid embedding types that interfere with serialization.

type Event struct {
    Name string    `json:"name"`
    Time time.Time `json:"time"`
}

(2) Incorrect time comparison

Comparing two time.Time values with the == operator checks both wall‑clock and monotonic clock components, often yielding false negatives.

t1 := time.Now()
t2 := t1.Add(1 * time.Second)
fmt.Println(t1 == t2) // wrong comparison

Best practice: Use the Equal method, which compares only the wall‑clock time.

fmt.Println(t1.Equal(t2)) // correct comparison

(3) Numeric type assertion issues

When unmarshaling JSON into an interface{} map, numbers default to float64. Directly asserting them as int causes a runtime panic.

var m map[string]any
json.Unmarshal([]byte(`{"key":123}`), &m)
fmt.Println(m["key"].(int)) // panic

Best practice: Assert to float64 first, then convert, or use a safer type‑assertion pattern.

if val, ok := m["key"].(float64); ok {
    fmt.Println(int(val)) // safe conversion
}

4. SQL operation pitfalls

(1) Forgetting to verify the database connection

sql.Open

only validates the arguments; it does not establish a live connection. Errors surface later during queries.

db, _ := sql.Open("mysql", "user:pass@/db") // no connection test

Best practice: Call Ping after opening to ensure the connection is valid.

if err := db.Ping(); err != nil {
    fmt.Println("FunTester database connection failed:", err)
    return
}

(2) Forgetting to close query results

Neglecting to close Rows leaves connections open, eventually exhausting the pool.

rows, _ := db.Query("SELECT * FROM table") // rows not closed

Best practice: Defer rows.Close() immediately after a successful query.

rows, err := db.Query("SELECT * FROM table")
if err != nil {
    return
}
defer rows.Close()

5. HTTP handling pitfalls

(1) Forgetting to return after writing an error response

Continuing execution after sending an error can produce additional output and corrupt the response.

func handler(w http.ResponseWriter, r *http.Request) {
    http.Error(w, "Error", http.StatusInternalServerError)
    // missing return – extra content may be written
    fmt.Fprintln(w, "Extra content")
}

Best practice: Return immediately after handling the error.

func handler(w http.ResponseWriter, r *http.Request) {
    http.Error(w, "FunTester error", http.StatusInternalServerError)
    return
}

(2) Using the default HTTP client without a timeout

The default http.Get has no timeout, which can cause requests to hang indefinitely.

http.Get("http://example.com") // no timeout

Best practice: Create a custom http.Client with a reasonable timeout.

client := &http.Client{Timeout: 10 * time.Second}
client.Get("http://example.com")

Conclusion

The Go standard library is powerful, but subtle mistakes—especially around time handling, resource management, JSON serialization, SQL usage, and HTTP responses—can lead to performance degradation, memory leaks, or runtime crashes. By following the best‑practice guidelines presented above, developers can write Go code that is both efficient and robust.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performanceGobest practicesError HandlingStandard Library
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.