owasp-amass/amass · error

failed to find the level key

Error message

failed to find the level key

What it means

After unmarshalling, JSONLogToRecord looks up slog.LevelKey ("level") in the parsed map; if the key is absent, no slog level can be assigned to the record and this error is returned. The library requires every engine log line to carry an explicit level field.

Source

Thrown at internal/afmt/slog.go:36

	// unmarshal the log message sent from the engine session
	if err := json.Unmarshal([]byte(logstr), &j); err != nil {
		return slog.Record{}, errors.New("failed to unmarchal the JSON")
	}

	ltime := time.Now()
	if timeVal, found := j[slog.TimeKey]; found {
		if timestr, valid := timeVal.(string); valid {
			if t, err := time.Parse("2006-01-02T15:04:05.000000000Z", timestr); err == nil {
				ltime = t
			}
		}
	}
	delete(j, slog.TimeKey)

	var level slog.Level
	// extract the log level for the new record
	if val, found := j[slog.LevelKey]; !found {
		return slog.Record{}, errors.New("failed to find the level key")
	} else if str, ok := val.(string); !ok {
		return slog.Record{}, errors.New("failed to cast the level value")
	} else if level.UnmarshalText([]byte(str)) != nil {
		return slog.Record{}, errors.New("failed to unmarshal the level text")
	}
	delete(j, slog.LevelKey)

	var msg string
	// extract the log message for the new record
	if val, found := j[slog.MessageKey]; !found {
		return slog.Record{}, errors.New("failed to find the msg key")
	} else if str, ok := val.(string); !ok {
		return slog.Record{}, errors.New("failed to cast the msg value")
	} else {
		msg = str
	}
	delete(j, slog.MessageKey)

View on GitHub (pinned to 79299dce87)

Solutions

  1. Ensure every log line written by the engine includes a "level" field (e.g. via a slog handler that always adds it)
  2. Check engine and consumer versions match so log schemas agree
  3. Validate the required keys (time, level, msg) before calling JSONLogToRecord and route non-conforming lines elsewhere
  4. Inspect the offending line to confirm the key spelling is exactly "level"

Example fix

// before
{"time":"2026-09-06T10:00:00.000000000Z","msg":"started"}
// after
{"time":"2026-09-06T10:00:00.000000000Z","level":"INFO","msg":"started"}
Defensive patterns

Strategy: validation

Validate before calling

var probe map[string]any
if err := json.Unmarshal([]byte(logstr), &probe); err != nil {
    return err
}
if _, ok := probe[slog.LevelKey]; !ok {
    return errors.New("log line missing 'level' key")
}

Type guard

func hasLevelKey(j map[string]any) bool {
    _, ok := j[slog.LevelKey]
    return ok
}

Try / catch

rec, err := afmt.JSONLogToRecord(line)
if err != nil {
    if strings.Contains(err.Error(), "failed to find the level key") {
        rawLog.Printf("log line without level dropped: %q", line)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: JSONLogToRecord (via WriteLogMessage) receives a valid JSON object that lacks a "level" field — e.g. hand-crafted log lines, events from a different component that only set msg/time, or an older engine version that omitted the level.

Common situations: Forwarding logs from a component whose JSON schema differs; engine version downgrade/upgrade changing log schema; injecting custom events into the log stream without a level key.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of owasp-amass/amass@79299dce87 (2026-09-06). Data as JSON: /api/errors/a5d5332a16b12f32. Report an issue: GitHub.