unknwon/the-way-to-go_ZH_CN · error

%d is out of the int32 range

Error message

%d is out of the int32 range

What it means

Chapter 13 exercise (panic_defer_convint.go): ConvertInt64ToInt panics with fmt.Sprintf("%d is out of the int32 range", l) when the int64 argument falls outside [math.MinInt32, math.MaxInt32]. Its wrapper IntFromInt64 demonstrates converting a panic into an error: a deferred recover catches the panic and builds err via fmt.Errorf("%v", e), so callers get a formatted range error instead of a crash — which is exactly what main tests with math.MaxInt32 + 15000.

Source

Thrown at eBook/exercises/chapter_13/panic_defer_convint.go:29

	if i, err := IntFromInt64(l); err != nil {
		fmt.Printf("The conversion of %d to an int32 resulted in an error: %s", l, err.Error())
	} else {
		fmt.Printf("%d converted to an int32 is %d", l, i)
	}
	fmt.Println()
	l = int64(math.MaxInt32 + 15000)
	if i, err := IntFromInt64(l); err != nil {
		fmt.Printf("The conversion of %d to an int32 resulted in an error: %s", l, err.Error())
	} else {
		fmt.Printf("%d converted to an int32 is %d", l, i)
	}
}

func ConvertInt64ToInt(l int64) int {
	if math.MinInt32 <= l && l <= math.MaxInt32 {
		return int(l)
	}
	panic(fmt.Sprintf("%d is out of the int32 range", l))
}

func IntFromInt64(l int64) (i int, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = fmt.Errorf("%v", e)
		}
	}()
	i = ConvertInt64ToInt(l)
	return i, nil
}

/* Output:
15000 converted to an int32 is 15000
The conversion of 2147498647 to an int32 resulted in an error: 2147498647 is out of the int32 range
*/

View on GitHub (pinned to 7a54d34d36)

Solutions

  1. Call IntFromInt64 (the recover wrapper) instead of ConvertInt64ToInt when the value is untrusted — it returns the error instead of crashing the process
  2. Pre-check the range: if l < math.MinInt32 || l > math.MaxInt32 { handle } before any conversion
  3. Redesign the API to return an error natively (range check + return 0, err) and reserve panic for programmer errors — the generalization of this exercise
  4. Where possible keep values int64 end-to-end so no narrowing conversion exists

Example fix

// before
i := ConvertInt64ToInt(l) // panics on out-of-range; crashes the program

// after
i, err := IntFromInt64(l)
if err != nil {
	log.Fatalf("conversion failed: %v", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if l < math.MinInt32 || l > math.MaxInt32 {
	return 0, fmt.Errorf("%d does not fit int32; rejecting before conversion", l)
}
return int(l), nil

Try / catch

i, err := IntFromInt64(l) // recovers the range panic into an error
if err != nil {
	return fmt.Errorf("narrowing %d: %v", l, err)
}

Prevention

When it happens

Trigger: ConvertInt64ToInt(l) with any l beyond ±(2^31-1): the range check math.MinInt32 <= l && l <= math.MaxInt32 fails and the panic fires. Calling IntFromInt64(l) instead turns it into the returned error, printing 'The conversion of 2148979647 to an int32 resulted in an error: ...'.

Common situations: Nanosecond timestamps, hashes, database IDs, and file sizes exceeding 2^31; migrating code between 32/64-bit platforms where int/int64 widths differ; the exercise's own lesson — converting panicking library calls into error returns at a package boundary.

Related errors


AI-assisted analysis of unknwon/the-way-to-go_ZH_CN@7a54d34d36 (2026-08-15). Data as JSON: /api/errors/f28a5214000209c9. Report an issue: GitHub.