owasp-amass/amass · error

failed to cast the level value

Error message

failed to cast the level value

What it means

When the "level" key is present in the parsed JSON but its value is not a JSON string (e.g. a number like 3 or null), the type assertion val.(string) fails and this error is returned. slog.Level.UnmarshalText expects textual level names (DEBUG, INFO, WARN, ERROR), so a non-string level cannot be converted.

Source

Thrown at internal/afmt/slog.go:38

		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)

	var pc uintptr
	record := slog.NewRecord(ltime, level, msg, pc)

View on GitHub (pinned to 79299dce87)

Solutions

  1. Produce log levels as strings ("DEBUG","INFO","WARN","ERROR") in the engine's JSON output
  2. If you control the producer, convert numeric levels to text before writing the line
  3. If you cannot change the producer, pre-process the JSON map and stringify numeric levels before calling JSONLogToRecord
  4. Check producer/consumer library versions for schema agreement

Example fix

// before
{"time":"...","level":3,"msg":"started"}
// after
{"time":"...","level":"INFO","msg":"started"}
Defensive patterns

Strategy: type-guard

Validate before calling

if v, ok := j[slog.LevelKey]; ok {
    if _, isStr := v.(string); !isStr {
        return errors.New("level value must be a JSON string")
    }
}

Type guard

func levelIsString(j map[string]any) bool {
    v, ok := j[slog.LevelKey]
    if !ok {
        return false
    }
    _, isStr := v.(string)
    return isStr
}

Try / catch

rec, err := afmt.JSONLogToRecord(line)
if err != nil {
    if strings.Contains(err.Error(), "failed to cast the level value") {
        rawLog.Printf("non-string level in log line: %q", line)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: JSONLogToRecord receives a log line where j["level"] is an int, float, bool, null, or nested object instead of a string.

Common situations: A producer serializing numeric log levels (0-4) while the consumer expects text; hand-written or tool-generated log lines; a schema mismatch between two library versions.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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