I have a variadic function respond
that takes several positional arguments and an any
slice spread at the end. Depending on the context, the function uses the last parameter in different ways (note how message
and data
differ depending on the value of status
.):
func respond(w http.ResponseWriter, status int, format string, a ...any) {
var (
statusOk bool
message string
data interface{}
)
if status >= 300 {
statusOk = false
message = fmt.Sprintf(format, a...)
data = nil
log.Error().Msg(message)
} else {
statusOk = true
message = format
data = a[0]
log.Info().Msg(fmt.Sprintf("%d", status))
}
// issue response
responder := render.New()
responder.JSON(w, status, map[string]interface{}{
"statusOk": statusOk,
"status": status,
"message": message,
"data": data,
})
}
For the call below I do not get any warnings:
respond(w, http.StatusNotFound, "person %v does not exist", personId)
For the next one, however, the warning respond call has arguments but no formatting directives
is raised (but the code runs as expected, person
is a struct
):
respond(w, http.StatusAccepted, "updated", person)
To my amateur eye, it looks like the variadic function expects to have a formatting string and parameters for this format at the end. But why would that be the case? Is there a limitation to what a variadic function is supposed to do?
Or should I better split responder
in two, one for each case ("ok" and "not ok")?
Also see https://github.com/golang/go/issues/26486 and https://go.dev/src/cmd/vet/testdata/print/print.go (line 316) for a discussion of that message in Go's code (what I have is a warning from a linter, as @mkopriva and @JimB mentioned in their comments)
The warning comes from the linter because you're calling the respond()
function with a format string not matching the arguments provided after that.
This specific message comes from the printf Analyzer which documents that:
printf: check consistency of Printf format strings and arguments
The check applies to calls of the formatting functions such as fmt.Printf and fmt.Sprintf, as well as any detected wrappers of those functions.
Since your response()
function uses the format
and a
parameters to call fmt.Sprintf()
as-is, this is considered as a wrapper for fmt.Sprintf()
.
If you want to avoid / get rid of this warning message, the easiest "fix" is to not use those parameters as-is, e.g. make a copy of one of the arguments, and pass that:
// Make and use a copy to avoid being marked as a wrapper of fmt.Sprintf
format := format
message = fmt.Sprintf(format, a...)