dapr/dapr · error

name is a path traversal sequence: %q

Error message

name is a path traversal sequence: %q

What it means

ValidateName rejects the exact names '.' and '..'. Because the name is embedded in a URL path, a relative path segment could resolve to an unexpected route on the actor host (path traversal), so the two dot forms are refused outright even though they contain no forbidden character. The error quotes the offending name for the log.

Source

Thrown at pkg/messaging/method/normalize.go:37

	"strings"
)

// ValidateName checks that a name (e.g. reminder or timer name) does not
// contain characters that could cause path traversal or injection when the
// name is embedded in a URL path. Unlike NormalizeMethod, this rejects any
// name containing '/' or '\' since names are identifiers, not paths.
func ValidateName(name string) error {
	if strings.ContainsAny(name, "#?\x00/\\") {
		return fmt.Errorf("name contains forbidden character: %q", name)
	}
	for i := range name {
		b := name[i]
		if b < 0x20 || b == 0x7f {
			return fmt.Errorf("name contains control character at position %d: %q", i, name)
		}
	}
	if name == "." || name == ".." {
		return fmt.Errorf("name is a path traversal sequence: %q", name)
	}
	return nil
}

// NormalizeMethod validates and cleans a service invocation method name.
// It rejects methods containing '#', '?', null bytes, or control characters
// (bytes 0x01-0x1f and 0x7f), then resolves path traversal via path.Clean.
// The caller is responsible for percent-decoding (for HTTP) before calling.
func NormalizeMethod(method string) (string, error) {
	if strings.ContainsAny(method, "#?\x00") {
		return "", fmt.Errorf("method contains forbidden character: %q", method)
	}

	// Reject control characters (0x01-0x1f and 0x7f DEL).
	for i := range method {
		b := method[i]
		if b < 0x20 || b == 0x7f {
			return "", fmt.Errorf("method contains control character at position %d: %q", i, method)

View on GitHub (pinned to 74ad417027)

Solutions

  1. Require a meaningful name: minimum length and an allowlist charset (letters, digits, '_', '-', '.') that also rejects all-dot names
  2. Default empty names to a generated ID instead of letting a dot fall through
  3. Add a unit test asserting your name generator never emits '.', '..', or empty strings

Example fix

// before: derived name can collapse to '..'
name := path.Clean(userPath) // '..'
client.CreateReminder(ctx, actorType, actorID, name, r)
// -> name is a path traversal sequence: ".."

// after: validate names through one guarded helper
func safeName(s string) (string, error) {
	if !regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`).MatchString(s) || s == "." || s == ".." {
		return "", fmt.Errorf("invalid reminder name %q", s)
	}
	return s, nil
}
Defensive patterns

Strategy: validation

Validate before calling

var safeNameRe = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`)

func safeReminderName(s string) (string, error) {
	if !safeNameRe.MatchString(s) || s == "." || s == ".." {
		return "", fmt.Errorf("invalid name %q", s)
	}
	return s, nil
}

Type guard

func isPathTraversalName(name string) bool {
	return name == "." || name == ".."
}

Try / catch

if err := client.CreateReminder(ctx, actorType, actorID, name, r); err != nil {
	if strings.Contains(err.Error(), "path traversal sequence") {
		return badRequest("name must be a meaningful identifier")
	}
	return err
}

Prevention

When it happens

Trigger: Creating a reminder or timer named exactly '.' or '..': usually a defaulted, empty-ish, or path-normalized value (basename of an empty path, a config default, a TrimSpace leftover) passed as the name.

Common situations: Config templates whose name field is optional and normalizes to '.'; code that derives names from file paths and passes the cleaned relative segment; test fixtures using dot names.

Related errors


AI-assisted analysis of dapr/dapr@74ad417027 (2026-08-16). Data as JSON: /api/errors/09ee9c28cef6dcdf. Report an issue: GitHub.