OrchardCMS/OrchardCore · error · InvalidOperationException

The SMTP pickup directory location

Error message

The SMTP pickup directory location '{pickupDirectoryLocation}' resolves outside the configured pickup directory base '{pickupDirectoryLocationBase}'.

What it means

After resolving the configured pickup directory location against the base path with Path.GetFullPath/Combine, the resolver verifies the result stays within the base (IsWithinBasePath). If the resolved path escapes the configured base directory, it throws InvalidOperationException to block path traversal.

Solutions

  1. Configure a pickup directory location that resolves inside the configured base directory.
  2. Remove '..' segments or absolute paths that escape the base; use subfolders of the base instead.
  3. Update the pickup directory base setting itself if the intended target genuinely lies elsewhere.
  4. Verify the final path stays within the base before saving settings (use the resolver's IsValid/IsWithinBasePath helpers).

Example fix

// before
"PickupDirectoryLocation": "..\\OtherSite\\Pickup"
// after
"PickupDirectoryLocation": "Pickup" // resolves inside the configured base directory
Defensive patterns

Strategy: validation

Validate before calling

var full = Path.GetFullPath(Path.Combine(basePath, location));
if (!full.StartsWith(Path.GetFullPath(basePath), StringComparison.OrdinalIgnoreCase))
    throw new InvalidOperationException("Pickup directory must stay within the configured base.");

Try / catch

try { var dir = SmtpPickupDirectoryResolver.ResolvePickupDirectoryLocation(basePath, location); } catch (InvalidOperationException ex) when (ex.Message.Contains("outside the configured pickup directory base")) { /* reject the setting and prompt admin */ }

Prevention

When it happens

Trigger: PickupDirectoryLocation contains traversal segments such as '..' or rooted/absolute paths that, when combined with the base, resolve outside the base directory; the guard throws before returning the path.

Common situations: Administrator enters a relative path with '../' segments, or a value pointing at a different drive/root; security-hardened deployments where the base is intentionally locked down and the configured value tries to escape it.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of OrchardCMS/OrchardCore@4306c0717f (2026-09-13). Data as JSON: /api/errors/d3e42f081490cebd. Report an issue: GitHub.

Appendix: source

Thrown at src/OrchardCore.Modules/OrchardCore.Email.Smtp/Services/SmtpPickupDirectoryResolver.cs:73

    public static string ResolvePickupDirectoryLocation(string pickupDirectoryLocationBase, string pickupDirectoryLocation)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(pickupDirectoryLocationBase);

        if (!IsValidPickupDirectoryLocation(pickupDirectoryLocation))
        {
            throw new InvalidOperationException("The SMTP pickup directory location is invalid.");
        }

        var normalizedPickupDirectoryLocation = NormalizePickupDirectoryLocation(pickupDirectoryLocation);

        var fullPickupDirectoryLocation = string.IsNullOrWhiteSpace(normalizedPickupDirectoryLocation)
            ? pickupDirectoryLocationBase
            : Path.GetFullPath(Path.Combine(pickupDirectoryLocationBase, normalizedPickupDirectoryLocation));

        if (!IsWithinBasePath(pickupDirectoryLocationBase, fullPickupDirectoryLocation))
        {
            throw new InvalidOperationException($"The SMTP pickup directory location '{pickupDirectoryLocation}' resolves outside the configured pickup directory base '{pickupDirectoryLocationBase}'.");
        }

        return fullPickupDirectoryLocation;
    }

    public static bool IsValidPickupDirectoryLocation(string pickupDirectoryLocation)
    {
        if (string.IsNullOrWhiteSpace(pickupDirectoryLocation))
        {
            return true;
        }

        pickupDirectoryLocation = pickupDirectoryLocation.Trim();

        if (pickupDirectoryLocation.IndexOfAny(s_invalidPickupDirectoryLocationCharacters) >= 0 ||
            pickupDirectoryLocation.Contains("{%", StringComparison.Ordinal))
        {
            return false;

View on GitHub (pinned to 4306c0717f)