projectdiscovery/katana · error
error decoding: %v
Error message
error decoding: %v
What it means
The mapstructure decoder failed to convert the result struct into a map[string]any using its json tags. Decode returns an error when field types are incompatible with the target map (e.g., unsupported kinds) or a field cannot be converted. evalDslExpr then cannot evaluate the expression against the result data.
Source
Thrown at pkg/output/output.go:438
gologger.Error().Msgf("Could not evaluate DSL expression: %s\n", err)
return false
}
return res == true
}
func resultToMap(result Result) (map[string]interface{}, error) {
resultMap := make(map[string]any)
config := &mapstructure.DecoderConfig{
TagName: "json",
Result: &resultMap,
}
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
return nil, fmt.Errorf("error creating decoder: %v", err)
}
err = decoder.Decode(result)
if err != nil {
return nil, fmt.Errorf("error decoding: %v", err)
}
requestMap := make(map[string]any)
if err := mapstructure.Decode(result.Request, &requestMap); err == nil {
for k, v := range requestMap {
resultMap[strcase.SnakeCase(k)] = v
}
}
responseMap := make(map[string]any)
if err := mapstructure.Decode(result.Response, &responseMap); err == nil {
for k, v := range responseMap {
if strings.ToLower(k) == "headers" {
if headers, ok := v.(navigation.Headers); ok {
for hk, hv := range headers {
resultMap[strcase.SnakeCase(hk)] = hv
}
}View on GitHub (pinned to e3e742739c)
Solutions
- Read the wrapped %v error to find the exact failing field, then fix that field's type or add a json tag.
- Add WeaklyTypedInput: true to DecoderConfig if string/number coercions are the problem.
- Ensure all exported fields on the result struct have json tags and no func/chan/circular fields.
- Use a custom DecodeHook (e.g., StringToTimeHookFunc) for types mapstructure can't handle natively.
Example fix
// before
config := &mapstructure.DecoderConfig{TagName: "json", Result: &resultMap}
// after
config := &mapstructure.DecoderConfig{
TagName: "json",
Result: &resultMap,
WeaklyTypedInput: true,
DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339),
} Defensive patterns
Strategy: validation
Validate before calling
// ensure result fields are decodable before calling resultToMap
rv := reflect.ValueOf(result).Elem()
for i := 0; i < rv.NumField(); i++ {
f := rv.Field(i)
if !f.CanInterface() {
continue
}
switch f.Kind() {
case reflect.Func, reflect.Chan, reflect.UnsafePointer:
return fmt.Errorf("field %s is not map-decodable", rv.Type().Field(i).Name)
}
} Type guard
func isMapDecodable(v any) bool {
rv := reflect.ValueOf(v)
return rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct
} Try / catch
resultMap, err := resultToMap(result)
if err != nil {
if strings.HasPrefix(err.Error(), "error decoding") {
log.Printf("result decode failed, evaluating DSL on raw value: %v", err)
resultMap = fallbackRawMap(result)
}
} Prevention
- Give every exported result field a json tag and keep types map-friendly (string, number, bool, slices, nested maps).
- Add DecodeHookFuncs for time.Time and other special types.
- Test DSL evaluation against realistic extraction results, not just primitives.
When it happens
Trigger: decoder.Decode(result) hits a result struct field whose value cannot be mapped into map[string]any: nested unexported fields that can't be reflected, circular structures, or incompatible types under json tag naming.
Common situations: Matching/extraction results containing custom types without json tags or with func/chan fields; extracting values from a response whose structure changed after an upstream library upgrade; using time.Time or nested pointers the configured decoder can't flatten with the default settings.
Related errors
AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03).
Data as JSON: /api/errors/ccc463c873257a97.
Report an issue: GitHub.