What does strconv.Atoi return when the input string is not a valid integer?
answer
- two results, not an exception
- what is the int when parsing fails?
- that value is a usable setting
- check err before trusting the number
basics
~20 sstrconv.Atoi returns two values, the parsed int and an error. On bad input it returns 0 plus a non-nil error rather than panicking, so the 0 is meaningless until you have checked that the error is nil.
solid answer
~40 sThe signature is `func Atoi(s string) (int, error)`. When the string is not a valid integer it returns `0` and a non-nil error, specifically a `*strconv.NumError` whose `Err` field is `strconv.ErrSyntax`; nothing panics and no exception is thrown. That matters because the zero it hands back is a perfectly usable `int`, so `n, _ := strconv.Atoi(os.Getenv("MAX_CONNS"))` starts the process with a connection limit of 0 and no complaint anywhere. Atoi is the decimal shorthand for `strconv.ParseInt(s, 10, 0)`, so it accepts an optional leading `+` or `-` and nothing else: no surrounding whitespace, no `1_000`, no `12.0`, no trailing units. The rule is to check `err` on every parse and decide the fallback explicitly, rather than letting the zero value become the setting.
code
go · 3 lines// MAX_CONNS unset, misspelled, or written as "1_000":
// all three end up here as a connection limit of 0.
maxConns, _ := strconv.Atoi(os.Getenv("MAX_CONNS"))go deeper
Recall the signature out loud: strconv.Atoi takes a string and returns an int and an error. Be ready to say that a failed parse gives you 0, not a panic, and that you must check the error before using the number.
Explain why the strictness exists: Atoi is ParseInt with base 10 and no bit-size limit, so whitespace, underscores and 0x prefixes are all syntax errors. Name the error type and the two sentinels it can carry.
Show the operational consequence. Talk through how a discarded error turns a missing environment variable into a limit of 0, and describe the startup log line that prints every resolved setting alongside its source so the mistake is visible before traffic arrives.
Own the convention rather than the call. Decide whether configuration parse failures abort startup or fall back to defaults, make that rule the same in every service, and make sure defaults are written down as constants instead of arriving as an accident of Go's zero value.
## The signature is the whole answer ```go func Atoi(s string) (int, error) ``` `strconv.Atoi` ("ASCII to integer") converts a decimal string to an `int`. Like nearly every fallible operation in Go it reports failure through a second return value rather than an exception. There is no throwing variant, no `TryParse` twin, and no sentinel like C's `atoi` returning `-1`. On failure you get **the zero value of the first result plus a non-nil error**. That is the entire trap. In a language where a bad parse throws, forgetting to handle it stops the program at the point of the mistake. In Go, forgetting to handle it produces a number. ## What the error is The error is a `*strconv.NumError`: ```go type NumError struct { Func string // the failing function, here "Atoi" Num string // the input string Err error // ErrSyntax or ErrRange } ``` Its `Error()` method renders as `strconv.Atoi: parsing "12x": invalid syntax`, so the offending input is already quoted inside the message and you rarely need to append it again when logging. `Err` is one of two package-level sentinels: `strconv.ErrSyntax` when the text is not a number at all, and `strconv.ErrRange` when the digits are valid but the value does not fit an `int`. ## What counts as invalid Atoi is deliberately strict, because it is `ParseInt(s, 10, 0)` underneath with only the error's `Func` field renamed: - `"42"` and `"+42"` and `"-42"` parse. - `"007"` parses as 7; the leading zero is not an octal signal here because the base is fixed at 10. - `" 42"` or `"42\n"` fail: no whitespace is trimmed. Call `strings.TrimSpace` yourself. - `""` fails. - `"42.0"` fails; that is `ParseFloat` territory. - `"1_000"` fails: underscore separators are accepted only when `ParseInt` is called with base 0. - `"0x1f"` fails for the same reason: prefix inference only happens at base 0. ## Why this bites a configuration loader The classic version of this bug lives in the code that reads the environment at process start: ```go maxConns, _ := strconv.Atoi(os.Getenv("MAX_CONNS")) ``` If `MAX_CONNS` is unset, misspelled in the deployment manifest, or written as `1_000` or `2k`, `maxConns` becomes 0. Nothing logs, nothing fails, and the service comes up with a limit of zero, which downstream code will interpret as "no connections allowed" or, more often, as "unlimited" because someone wrote `if maxConns > 0` around the guard. The failure surfaces hours later as saturation or as a service that refuses all work, a long way from the parse. The fix is not clever, it is only disciplined: ```go func maxConns() (int, error) { v := os.Getenv("MAX_CONNS") if v == "" { return 64, nil // the default is a decision, written down } n, err := strconv.Atoi(v) if err != nil { return 0, fmt.Errorf("MAX_CONNS=%q: %w", v, err) } return n, nil } ``` Two things changed. The empty case is now an explicit default rather than an accident of the zero value, and a malformed value stops startup instead of silently becoming a setting. A startup log line that prints every resolved setting next to where it came from turns the remaining mistakes into something you can read off the first ten lines of a deployment's logs. ## The sibling functions `Atoi` is one member of a small, regular family: `ParseInt` and `ParseUint` for other bases and widths, `ParseBool` for flags, and `Itoa` / `FormatInt` for the reverse direction. `ParseBool` is worth memorising because it is narrower than people expect: it accepts only `1`, `t`, `T`, `TRUE`, `true`, `True`, `0`, `f`, `F`, `FALSE`, `false`, `False`. `DEBUG=yes` and `DEBUG=on` are syntax errors, and a discarded error there means the flag reads as false forever. ## How to talk about it in an interview Say the signature, say that failure returns `0` and a non-nil `*strconv.NumError`, and then say the consequence out loud: the zero is indistinguishable from a legitimate configured zero unless you look at the error. Interviewers asking this are usually checking whether you have internalised Go's multiple-return error convention or are still writing the language you came from.
- What does the error from a failed strconv.Atoi actually contain?A `*strconv.NumError` with three fields: `Func` (here `"Atoi"`), `Num` (the input string) and `Err`, which is either `strconv.ErrSyntax` or `strconv.ErrRange`. Its message renders as `strconv.Atoi: parsing "12x": invalid syntax`, so the bad input is already quoted in the text and you do not need to append it again when logging.
- Does strconv.Atoi accept surrounding whitespace, a leading plus, or digit separators?A leading `+` or `-` is fine. Whitespace is not trimmed, so `" 42"` is a syntax error and you must call `strings.TrimSpace` first. `1_000` also fails: underscore separators are only permitted when `strconv.ParseInt` is called with base 0, and Atoi fixes the base at 10.
- Which strings does strconv.ParseBool accept for a boolean setting?Exactly `1`, `t`, `T`, `TRUE`, `true`, `True`, `0`, `f`, `F`, `FALSE`, `false` and `False`. Anything else, including `yes`, `on` and the empty string, returns a `*strconv.NumError` wrapping `strconv.ErrSyntax`. Discarding that error makes every unrecognised spelling read as false, which is how a feature flag quietly stays off.
saying these in an interview costs you the question
- Says a bad strconv.Atoi call panics or throws
- Uses the returned 0 without checking the error
- Thinks Atoi trims surrounding whitespace
- Expects -1 on failure, like C's atoi
- Believes the second result is a bool ok flag
- Treats an unset environment variable and a parsed 0 as the same case