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

  1. Read the wrapped %v error to find the exact failing field, then fix that field's type or add a json tag.
  2. Add WeaklyTypedInput: true to DecoderConfig if string/number coercions are the problem.
  3. Ensure all exported fields on the result struct have json tags and no func/chan/circular fields.
  4. 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

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.