projectdiscovery/nuclei · error
object can be a key:value or a string
Error message
object can be a key:value or a string
What it means
SliceOrMapSlice (pkg/fuzz/type.go) backs the `fuzz:` payload field of fuzzing rules and accepts exactly two shapes: a flat array of strings or an object of string->string. UnmarshalJSON tries the array first, then the ordered map; if both fail (the JSON is a scalar, a nested array, an array of non-strings, or an object with non-string values), it returns this error and template/JSON parsing of the fuzz rule aborts.
Source
Thrown at pkg/fuzz/type.go:80
},
{
Type: "object",
},
},
},
}
return gotType
}
// UnmarshalJSON implements json.Unmarshaler interface.
func (v *SliceOrMapSlice) UnmarshalJSON(data []byte) error {
// try to unmashal as a string and fallback to map
if err := json.Unmarshal(data, &v.Value); err == nil {
return nil
}
err := json.Unmarshal(data, &v.KV)
if err != nil {
return fmt.Errorf("object can be a key:value or a string")
}
return nil
}
// MarshalJSON implements json.Marshaler interface.
func (v SliceOrMapSlice) MarshalJSON() ([]byte, error) {
if v.KV != nil {
return json.Marshal(v.KV)
}
return json.Marshal(v.Value)
}
// UnmarshalYAML implements yaml.Unmarshaler interface.
func (v *SliceOrMapSlice) UnmarshalYAML(callback func(interface{}) error) error {
// try to unmarshal it as a string and fallback to map
if err := callback(&v.Value); err == nil {
return nil
}View on GitHub (pinned to 265b3a3dec)
Solutions
- Use a flat array of quoted strings: "fuzz": ["'", "admin"]
- Or an object where every key and value is a string: "fuzz": {"user": "admin"}
- Quote numeric and boolean payloads so they marshal as JSON strings
- Validate the template with `nuclei -validate` before running it
Example fix
// before
"fuzz": {
"user": 123,
"nested": { "a": "b" }
}
// after
"fuzz": {
"user": "123"
} Defensive patterns
Strategy: type-guard
Validate before calling
var raw any
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
switch v := raw.(type) {
case []any:
for _, it := range v {
if _, ok := it.(string); !ok {
return fmt.Errorf("fuzz payload array must contain only strings")
}
}
case map[string]any:
for _, val := range v {
if _, ok := val.(string); !ok {
return fmt.Errorf("fuzz payload values must be strings")
}
}
default:
return fmt.Errorf("fuzz must be an array of strings or a string-to-string object")
} Type guard
func isSliceOrMapSliceJSON(data []byte) bool {
var arr []string
if json.Unmarshal(data, &arr) == nil {
return true
}
var m map[string]string
return json.Unmarshal(data, &m) == nil
} Try / catch
if err := json.Unmarshal(data, &v); err != nil {
if strings.Contains(err.Error(), "object can be a key:value or a string") {
return fmt.Errorf("invalid fuzz payload shape in %s: use [\"str\",...] or {\"k\":\"v\"}", path)
}
return err
} Prevention
- Always stringify fuzz payloads (quote numbers/booleans)
- Never nest arrays or objects inside the fuzz payload field
- Run template validation after any JSON round-trip through typed tooling
When it happens
Trigger: Supplying `"fuzz": 123` or `"fuzz": true` in JSON; an array with nested arrays or numbers like [["a"]] or [1,2]; an object whose values are objects, arrays, or unquoted numbers; programmatically marshaling a struct into the fuzz field and hitting a shape mismatch.
Common situations: Hand-writing fuzz rules in JSON tools or UIs that infer types (numbers, booleans) instead of strings; pipelines that generate templates from typed data and forget to stringify payloads; porting YAML templates to JSON and keeping YAML-style nested structures.
Related errors
- response read size must be non-negative
- empty filename
- invalid attack type: %s
- no new line found at the end of host header
- no fuzz values specified
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/1688b2aff11b1564.
Report an issue: GitHub.