shadow1ng/fscan · error

failed to marshal result: %w

Error message

failed to marshal result: %w

What it means

JSONWriter.Write marshals the ScanResult to JSON for the realtime NDJSON backup. This error is returned when json.Marshal fails. For a plain ScanResult this is rare and usually indicates an unmarshalable field (e.g. a channel, func, or cyclic reference added to the struct).

Source

Thrown at common/output/writers.go:525

func (w *JSONWriter) Write(result *ScanResult) error {
	w.mu.Lock()
	defer w.mu.Unlock()

	if w.closed {
		return fmt.Errorf("writer is closed")
	}
	if result == nil {
		return fmt.Errorf("result cannot be nil")
	}

	// 1. 加入内存分类缓冲(用于最终有序输出)
	w.buffer.Add(result)

	// 2. 实时写入备份文件(NDJSON格式,防崩溃丢失)
	if w.realtimeFile != nil {
		data, err := json.Marshal(result)
		if err != nil {
			return fmt.Errorf("failed to marshal result: %w", err)
		}
		if _, err := w.realtimeFile.Write(append(data, '\n')); err != nil {
			return fmt.Errorf("failed to write realtime backup: %w", err)
		}
		if err := w.realtimeFile.Sync(); err != nil {
			return fmt.Errorf("failed to sync realtime backup: %w", err)
		}
	}

	return nil
}

// Flush 刷新写入器
func (w *JSONWriter) Flush() error {
	return nil
}

// Close 关闭写入器(写入完整JSON,删除临时备份)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Remove or convert unmarshalable fields (channels/funcs/cycles) on ScanResult
  2. Check any custom MarshalJSON methods on result fields for returned errors
  3. Use json.Marshal on a sanitized/dto copy of the result
  4. Update the library if a recent ScanResult change introduced the bad field
  5. Reproduce with json.Marshal(result) standalone to identify the failing field

Example fix

// before
type ScanResult struct {
	Host string
	Conn net.Conn // not marshalable
}
// after
type ScanResult struct {
	Host string
}
func (r ScanResult) MarshalJSON() ([]byte, error) {
	return json.Marshal(map[string]string{"host": r.Host})
}
Defensive patterns

Strategy: validation

Validate before calling

func serializable(r *ScanResult) error {
	_, err := json.Marshal(r)
	return err
}
// call before writer.Write():
if err := serializable(result); err != nil { return err }

Try / catch

if err := writer.Write(result); err != nil {
	if strings.Contains(err.Error(), "failed to marshal result") {
		log.Printf("unmarshalable ScanResult (check custom MarshalJSON / new fields): %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling Write() with a ScanResult whose struct contains fields json.Marshal cannot encode: channels, funcs, cycles, or a custom MarshalJSON returning an error.

Common situations: Extending ScanResult with non-serializable runtime state (connections, callbacks); a custom type's MarshalJSON implementation erroring; embedding a raw map with unencodable keys/values.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/8c740fe5a93e7ad7. Report an issue: GitHub.