projectdiscovery/katana · error

error creating decoder: %v

Error message

error creating decoder: %v

What it means

mapstructure.NewDecoder failed while constructing a decoder for converting a result struct into a map using json tags. NewDecoder only errors on invalid DecoderConfig, practically meaning Result is not a non-nil pointer (here &resultMap is always valid), so this is nearly unreachable but defensively handled. If hit, DSL evaluation in evalDslExpr cannot proceed.

Source

Thrown at pkg/output/output.go:434

	}

	res, err := dsl.EvalExpr(dslExpr, resultMap)
	if err != nil && !ignoreErr(err) {
		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 {

View on GitHub (pinned to e3e742739c)

Solutions

  1. Confirm DecoderConfig.Result is a non-nil pointer: Result: &resultMap with resultMap declared as map[string]any.
  2. Pin/upgrade github.com/mitchellh/mapstructure to a stable version; a broken vendored copy can misbehave.
  3. Log the underlying error (%v) — it states exactly which config field is invalid.
  4. If a refactor introduced this, revert the change to the DecoderConfig construction.

Example fix

// before
var resultMap map[string]any
config := &mapstructure.DecoderConfig{TagName: "json", Result: resultMap}
// after
resultMap := make(map[string]any)
config := &mapstructure.DecoderConfig{TagName: "json", Result: &resultMap}
Defensive patterns

Strategy: try-catch

Validate before calling

if result == nil || reflect.ValueOf(result).Kind() != reflect.Ptr {
    return nil, fmt.Errorf("resultToMap requires a non-nil pointer target")
}

Type guard

func isDecoderConfigValid(cfg *mapstructure.DecoderConfig) bool {
    return cfg != nil && cfg.Result != nil && reflect.ValueOf(cfg.Result).Kind() == reflect.Ptr && !reflect.ValueOf(cfg.Result).IsNil()
}

Try / catch

m, err := resultToMap(result)
if err != nil {
    if strings.HasPrefix(err.Error(), "error creating decoder") {
        // programmer error in DecoderConfig construction — fail fast with stack trace
    }
}

Prevention

When it happens

Trigger: resultToMap builds a DecoderConfig and NewDecoder rejects it — only possible if the Result target is nil or not a pointer, which would require resultMap to be nil or the config struct corrupted.

Common situations: Practically never seen in production; encountered when refactoring resultToMap (e.g., passing a nil map pointer or removing the & on Result) or when a vendored/patched mapstructure version has stricter config validation.

Related errors


AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03). Data as JSON: /api/errors/46d36ee2cbd01637. Report an issue: GitHub.