uber-go/zap · warning

must specify logging level

Error message

must specify logging level

What it means

The HTTP log-level handler's PUT /log/level endpoint (URL form mode) requires a `level` form/query value. decodePutURL returns errors.New("must specify logging level") when the `level` parameter is absent or empty before attempting UnmarshalText.

Source

Thrown at http_handler.go:123

		w.WriteHeader(http.StatusMethodNotAllowed)
		return enc.Encode(errorResponse{
			Error: "Only GET and PUT are supported.",
		})
	}
}

// Decodes incoming PUT requests and returns the requested logging level.
func decodePutRequest(contentType string, r *http.Request) (zapcore.Level, error) {
	if contentType == "application/x-www-form-urlencoded" {
		return decodePutURL(r)
	}
	return decodePutJSON(r.Body)
}

func decodePutURL(r *http.Request) (zapcore.Level, error) {
	lvl := r.FormValue("level")
	if lvl == "" {
		return 0, errors.New("must specify logging level")
	}
	var l zapcore.Level
	if err := l.UnmarshalText([]byte(lvl)); err != nil {
		return 0, err
	}
	return l, nil
}

func decodePutJSON(body io.Reader) (zapcore.Level, error) {
	var pld struct {
		Level *zapcore.Level `json:"level"`
	}
	if err := json.NewDecoder(body).Decode(&pld); err != nil {
		return 0, fmt.Errorf("malformed request body: %v", err)
	}
	if pld.Level == nil {
		return 0, errors.New("must specify logging level")
	}

View on GitHub (pinned to bbd4ecbd87)

Solutions

  1. Include the level in the request, e.g. curl -X PUT 'http://host:port/log/level?level=debug' or send form value level=debug
  2. Use a valid zapcore.Level text value (debug, info, warn, error, dpanic, panic, fatal)

Example fix

// before
curl -X PUT http://localhost:8080/log/level
// after
curl -X PUT 'http://localhost:8080/log/level?level=warn'
Defensive patterns

Strategy: validation

Validate before calling

// client side
if lvl == "" {
    return errors.New("level query/form parameter is required")
}
req, _ := http.NewRequest(http.MethodPut, fmt.Sprintf("http://host/log/level?level=%s", url.QueryEscape(lvl)), nil)

Try / catch

resp, err := client.Do(req)
if err != nil || resp.StatusCode != http.StatusOK {
    body, _ := io.ReadAll(resp.Body)
    return fmt.Errorf("set level failed: %s", body)
}

Prevention

When it happens

Trigger: Sending an HTTP PUT to the log-level handler endpoint without a `level` form value or query parameter, e.g. PUT /log/level with no body/params.

Common situations: Scripting level changes via curl and forgetting ?level=warn; proxies stripping query parameters; empty form posts.

Related errors


AI-assisted analysis of uber-go/zap@bbd4ecbd87 (2026-08-31). Data as JSON: /api/errors/a8720ec4a11328d5. Report an issue: GitHub.