← Debugging Guides

阅读中文版本

Go vet: Printf format %d has arg of wrong type

Fix go vet printf warnings when format verbs do not match argument types, and understand why fmt still prints apparently correct output.

beginnerdebugginggovetformatting

Symptoms

  • printf: fmt.Sprintf call has arguments but no formatting directives
  • Printf format %d has arg x of wrong type string
  • go vet fails CI even though the program prints plausible output

Possible causes

  • A format verb does not match the argument type (%d with a string)
  • A custom type has no String() method, so %s prints a struct
  • A recursive Printf call passes a format string built from user input
  • Arguments are missing or extra relative to the verbs

Diagnosis steps

Read the exact vet message and the argument type

Interpretation

vet names the format, the verb, and the Go type of the argument, which pinpoints the mismatch.

Compare verbs to argument order

Interpretation

A shifted argument list often makes every subsequent verb wrong, not just one.

Run vet across the module

go vet ./...

Interpretation

vet also flags Printf-like wrappers, catching helpers that forward formats unsafely.

Root cause

fmt uses reflection at run time and will happily print a mis-typed argument with placeholder text such as %!d(string=abc), so tests may pass while output is wrong. go vet performs static analysis of format strings and argument types and reports the mismatch before it reaches users.

Fix

Match each verb to its argument type (%d integers, %s strings, %v any, %q quoted). Add a String() method to custom types you print with %s. Ensure wrapper functions that build format strings are marked, and never construct a format string from untrusted input — pass it as a value with %v instead.

Verify the fix

Run `go vet ./...`; it reports no printf issues and CI passes, while a test asserting the formatted string confirms the output is now correct.

Symptoms

go vet fails with a message like Printf format %d has arg x of wrong type string, yet the program appears to print sensible output at run time.

Diagnosis

Read the verb, the argument type, and the call site together:

count := "5"
log.Printf("count=%d", count) // vet: %d with string

Check argument order too — one shifted value misaligns every following verb.

Fix

Align verbs and types, and implement String() for custom types:

log.Printf("count=%s", count)   // string

type Money struct{ Cents int }
func (m Money) String() string { return fmt.Sprintf("%.2f", float64(m.Cents)/100) }
log.Printf("total=%s", Money{1250})

Verification

go vet ./... passes and a unit test asserting the exact formatted output confirms the fix, since fmt would otherwise emit a %!d placeholder without erroring.

Additional Notes

Printf-style faults are dangerous precisely because they rarely crash: the formatter substitutes a placeholder and the program keeps running, so a log line quietly records the wrong value. Static analysis catches these before runtime, but only for format strings it can see literally, which is why wrappers that assemble formats dynamically deserve extra tests. Reviewing argument order whenever a message is edited is worthwhile, because inserting one value can misalign every verb after it and turn an otherwise correct string into misleading output.