projectdiscovery/katana · error

expression eval panic: %v

Error message

expression eval panic: %v

What it means

safeEvalExpr wraps dsl engine.EvalExpr with a recover() because the govaluate evaluation engine can panic on inputs that aren't valid expressions — most commonly plain strings treated as references to undefined variables. Instead of crashing, the panic is converted into this error and returned to the form-filling resolver.

Source

Thrown at pkg/utils/formfill.go:80

	}
	engine := getFormDSLEngine()
	if engine == nil {
		return value
	}
	result, err := safeEvalExpr(engine, value)
	if err != nil {
		return value
	}
	return fmt.Sprintf("%v", result)
}

// safeEvalExpr wraps engine.EvalExpr with panic recovery since the
// underlying govaluate library can panic on inputs that aren't
// valid expressions (e.g. plain strings treated as undefined variables).
func safeEvalExpr(engine *dsl.Engine, expr string) (result interface{}, err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("expression eval panic: %v", r)
		}
	}()
	return engine.EvalExpr(expr, map[string]interface{}{})
}

// Resolve evaluates all fields through the DSL engine, resolving any
// helper function calls like rand_email() or rand_password(8, true).
// Plain string values pass through unchanged.
func (f *FormFillData) Resolve() {
	f.Email = resolveField(f.Email)
	f.Color = resolveField(f.Color)
	f.Password = resolveField(f.Password)
	f.PhoneNumber = resolveField(f.PhoneNumber)
	f.Placeholder = resolveField(f.Placeholder)
}

// FormInput is an input for a form field
type FormInput struct {

View on GitHub (pinned to e3e742739c)

Solutions

  1. Quote/escape the value before evaluation, or bypass the DSL for values that are plain literals (pass them straight through).
  2. Check the %v panic message to identify the offending expression and fix the field's value in your form-fill config.
  3. Upgrade the govaluate dependency if a newer version handles the failing input without panicking.
  4. Pre-validate values with a regex for expression metacharacters and mark them as literals.

Example fix

// before
result, err := safeEvalExpr(engine, fieldValue) // panics on "O'Brien (work)"
// after
var result interface{}
var err error
if isPlainLiteral(fieldValue) {
    result = fieldValue
} else {
    result, err = safeEvalExpr(engine, fieldValue)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// treat values containing expression metacharacters as literals
var exprMeta = regexp.MustCompile(`[()&|!<>="']`)
func needsLiteral(v string) bool { return exprMeta.MatchString(v) }

Type guard

func isSafeExpression(s string) bool {
    // a safe expression references only known variables and operators
    return exprMeta.MatchString(s) == false || isQuotedString(s)
}

Try / catch

result, err := safeEvalExpr(engine, expr)
if err != nil {
    if strings.HasPrefix(err.Error(), "expression eval panic") {
        log.Printf("non-expression value %q, using as literal", expr)
        result = expr
        err = nil
    }
}

Prevention

When it happens

Trigger: Calling Resolve on form fields whose value expression is a literal string containing characters govaluate treats as expression syntax (quotes, operators, parentheses), causing engine.EvalExpr to panic internally and safeEvalExpr to recover and return "expression eval panic: %v".

Common situations: Auto-filling forms where the field value comes from arbitrary page data or user config; a value like "O'Brien (work)" or "a && b" interpreted as an expression instead of literal text; missing DSL escaping when values are meant to be plain strings.

Related errors


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