hashicorp/nomad · error

Unknown log level

Error message

Unknown log level

What it means

Nomad's agent HTTP 'monitor' streaming endpoint validates the requested log level before attaching a log sink. The requested LogLevel string is passed to log.LevelFromString; if it does not parse to a recognized hclog level, the result is log.NoLevel and the endpoint aborts the stream with this 400 error. It exists to fail fast with a clear message instead of silently falling back to a default level.

Source

Thrown at client/agent_endpoint.go:109

		return
	}

	// Check acl
	if aclObj, err := a.c.ResolveToken(args.AuthToken); err != nil {
		handleStreamResultError(err, new(int64(403)), encoder)
		return
	} else if !aclObj.AllowAgentRead() {
		handleStreamResultError(structs.ErrPermissionDenied, new(int64(403)), encoder)
		return
	}

	logLevel := log.LevelFromString(args.LogLevel)
	if args.LogLevel == "" {
		logLevel = log.LevelFromString("INFO")
	}

	if logLevel == log.NoLevel {
		handleStreamResultError(errors.New("Unknown log level"), new(int64(400)), encoder)
		return
	}

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	m := monitor.New(512, a.c.logger, &log.LoggerOptions{
		JSONFormat:      args.LogJSON,
		Level:           logLevel,
		IncludeLocation: args.LogIncludeLocation,
	})

	frames := make(chan *sframer.StreamFrame, streamFramesBuffer)
	errCh := make(chan error)
	var buf bytes.Buffer
	frameCodec := codec.NewEncoder(&buf, structs.JsonHandle)

	framer := sframer.NewStreamFramer(frames, 1*time.Second, 200*time.Millisecond, 1024)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Set log_level to one of TRACE, DEBUG, INFO, WARN, ERROR (case-insensitive) on the monitor request
  2. Omit log_level entirely to default to INFO
  3. Fix the caller/CLI wrapper so it maps friendly level names to hclog-valid levels
  4. Validate the level client-side before issuing the request

Example fix

// before
GET /v1/agent/monitor?log_level=warning
// after
GET /v1/agent/monitor?log_level=WARN
Defensive patterns

Strategy: validation

Validate before calling

validLevels := map[string]bool{"trace":true,"debug":true,"info":true,"warn":true,"error":true}
if logLevel != "" && !validLevels[strings.ToLower(logLevel)] {
  return fmt.Errorf("invalid log_level %q; must be TRACE|DEBUG|INFO|WARN|ERROR", logLevel)
}

Type guard

func isValidLogLevel(s string) bool {
  return s == "" || log.LevelFromString(s) != log.NoLevel
}

Try / catch

// Go: check the HTTP response before streaming
resp, err := c.Raw(agent.MonitorQuery{LogLevel: lvl})
if err != nil {
  if strings.Contains(err.Error(), "Unknown log level") {
    lvl = "INFO"
    return c.Raw(agent.MonitorQuery{LogLevel: lvl})
  }
  return err
}

Prevention

When it happens

Trigger: Calling the Agent Monitor API (GET /v1/agent/monitor) with query/log_level set to a string that is not one of TRACE, DEBUG, INFO, WARN, ERROR (case-insensitive), e.g. 'verbose', 'warning', 'all', or a typo like 'INF0'. An empty string is explicitly allowed (defaults to INFO).

Common situations: Hand-built HTTP requests or CLI wrappers passing an invalid --log-level flag; UI clients mapping user-chosen levels to wrong strings; automation scripts using 'warning' instead of 'WARN'.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/16f458610dc29042. Report an issue: GitHub.