owasp-amass/amass · error

failed to unmarchal the JSON

Error message

failed to unmarchal the JSON

What it means

JSONLogToRecord converts a JSON-formatted log line emitted by the engine session into a slog.Record. If json.Unmarshal fails on the input string, the function cannot proceed and returns this generic error (note the typo 'unmarchal' in the message). It throws because a non-JSON or truncated line cannot be mapped to a structured record.

Solutions

  1. Ensure the engine session writes one complete JSON object per line (JSON Lines format)
  2. Validate the input with json.Valid([]byte(logstr)) before calling JSONLogToRecord and log raw lines that fail
  3. Check for truncation — read full lines with a scanner and proper buffer size
  4. Confirm the engine and the log consumer use the same serialization options (no HTML escaping or custom field differences that break parsing)

Example fix

// before
if err := json.Unmarshal([]byte(logstr), &j); err != nil {
    return slog.Record{}, errors.New("failed to unmarchal the JSON")
}
// after
if !json.Valid([]byte(logstr)) {
    return slog.Record{}, fmt.Errorf("failed to unmarshal the JSON: %q", logstr)
}
if err := json.Unmarshal([]byte(logstr), &j); err != nil {
    return slog.Record{}, fmt.Errorf("failed to unmarshal the JSON: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

if !json.Valid([]byte(logstr)) {
    // route to raw-log sink instead of JSONLogToRecord
    return errors.New("not a JSON log line")
}

Try / catch

rec, err := afmt.JSONLogToRecord(line)
if err != nil {
    if strings.Contains(err.Error(), "unmarchal the JSON") {
        rawLog.Printf("non-JSON log line dropped: %q", line)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: WriteLogMessage receives a logstr that is not valid JSON: empty string, plain-text log line, partially written/truncated line from a broken pipe, or a line with a JSON-unrepresentable payload.

Common situations: Mixing human-readable and JSON log formats in the same stream; reading a line before the writer finished flushing; engine emitting a stack trace or multi-line message; encoding bugs upstream.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at internal/afmt/slog.go:20

// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// SPDX-License-Identifier: Apache-2.0

package afmt

import (
	"encoding/json"
	"errors"
	"fmt"
	"log/slog"
	"strconv"
	"time"
)

func JSONLogToRecord(logstr string) (slog.Record, error) {
	j := make(map[string]any)
	// 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")

View on GitHub (pinned to 79299dce87)