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
- Remove or convert unmarshalable fields (channels/funcs/cycles) on ScanResult
- Check any custom MarshalJSON methods on result fields for returned errors
- Use json.Marshal on a sanitized/dto copy of the result
- Update the library if a recent ScanResult change introduced the bad field
- 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
- Keep ScanResult free of channels, funcs, and cyclic references
- Test json.Marshal(ScanResult{}) in unit tests after struct changes
- Review any custom MarshalJSON implementations for error paths
- Use dto copies for serialization when runtime state must live on the struct
- Add a CI check that round-trips a fully populated ScanResult through JSON
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
- failed to write realtime backup: %w
- failed to sync realtime backup: %w
- failed to create JSON file: %w
- failed to create CSV file: %w
- parser_ipv4_only
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/8c740fe5a93e7ad7.
Report an issue: GitHub.