projectdiscovery/nuclei · error
unresolved DSL placeholder %q is not inside a string literal
Error message
unresolved DSL placeholder %q is not inside a string literal
What it means
Runtime resolution error from findDSLStringMarkers (pkg/operators/matchers/dsl_string_markers.go:93). For each expression found by expressions.FindExpressions (markers whose variables are absent from the data map), every literal occurrence of "{{expr}}" in the DSL source must lie fully inside a quoted string literal span. The first occurrence found outside string literals returns this error naming the placeholder.
Source
Thrown at pkg/operators/matchers/dsl_string_markers.go:93
for _, expr := range expressions.FindExpressions(expression, "{{", "}}", data) {
if _, ok := seenComplex[expr]; ok {
continue
}
seenComplex[expr] = struct{}{}
marker := "{{" + expr + "}}"
for start := 0; ; {
index := strings.Index(expression[start:], marker)
if index < 0 {
break
}
index += start
end := index + len(marker)
stringSpan, ok := stringLiteralForSpan(stringSpans, index, end)
if !ok {
return nil, fmt.Errorf("unresolved DSL placeholder %q is not inside a string literal", expr)
}
got := dslStringMarker{start: index, end: end, expr: expr, quote: stringSpan.quote}
markers = append(markers, got)
occupiedSpans = append(occupiedSpans, textSpan{start: index, end: end})
start = end
}
}
for _, match := range dslStringMarkerRegex.FindAllStringSubmatchIndex(expression, -1) {
if len(match) < 4 || markerWithinSpans(match[0], match[1], occupiedSpans) {
continue
}
stringSpan, ok := stringLiteralForSpan(stringSpans, match[0], match[1])
if !ok {
return nil, fmt.Errorf("unresolved DSL placeholder %q is not inside a string literal", expression[match[2]:match[3]])
}View on GitHub (pinned to 265b3a3dec)
Solutions
- Wrap the placeholder in quotes so it becomes a string literal: `"'{{needle}}'"`
- Correct or register the variable so it resolves before evaluation (e.g. ensure the generator defines it, or the referenced extractor ran)
- Provide a default via `{{var || 'fallback'}}`-style preprocessing upstream, or restructure to compare in a word matcher
- Enable -v logging to inspect which placeholder stays unresolved
Example fix
# before
dsl:
- 'contains(body, {{needle}})'
# after
dsl:
- "contains(body, '{{needle}}')" Defensive patterns
Strategy: validation
Validate before calling
// ensure every identifier referenced in the dsl exists in data, else require quoting
for _, v := range govaluateVars(dslExpr) {
if _, ok := data[v]; !ok && !strings.Contains(dslExpr, "'{{"+v+"}}'") {
return fmt.Errorf("variable %q unresolved and placeholder unquoted", v)
}
} Type guard
func markerInsideLiteral(expr, marker string, spans []stringLiteralSpan) bool { /* replicate stringLiteralForSpan check */ return true } Try / catch
if err := m.Match(data); err != nil && strings.Contains(err.Error(), "not inside a string literal") {
// quote the named placeholder and retest locally before redeploying
} Prevention
- Quote every {{placeholder}} used as a string operand in DSL matchers
- Verify generator payload names match marker names exactly
- Run templates with -v during development to inspect unresolved markers
When it happens
Trigger: An unresolved {{placeholder}} used as a bare govaluate operand — e.g. `status_code == {{code}}` or `contains(body, {{needle}})` — where the variable is not in the evaluation data, so the marker survives substitution and is then detected outside quotes.
Common situations: Generator/fuzz variables referenced as numbers or identifiers instead of quoted strings in DSL matchers; typos in variable names that never resolve; using an extractor name that produced no value for this request.
Related errors
- unresolved DSL placeholders must be inside string literals
- no records found
- failed to compile expression %q: %w
- failed to evaluate expression %q: %w
- payload concurrency must be at least 1
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/8c1a67d5424102b0.
Report an issue: GitHub.