{"record":{"id":"b1b4a98cc81f5577","repo":"OrchardCMS/OrchardCore","slug":"httprequest-missing-while-invoking-switch-culture-url","errorCode":null,"errorMessage":"HttpRequest missing while invoking 'switch_culture_url'","messagePattern":"HttpRequest missing while invoking 'switch_culture_url'","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/OrchardCore.Modules/OrchardCore.ContentLocalization/Liquid/SwitchCultureUrlFilter.cs","lineNumber":26,"sourceCode":"namespace OrchardCore.ContentLocalization.Liquid;\n\npublic class SwitchCultureUrlFilter : ILiquidFilter\n{\n    private readonly IUrlHelperFactory _urlHelperFactory;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n\n    public SwitchCultureUrlFilter(IUrlHelperFactory urlHelperFactory, IHttpContextAccessor httpContextAccessor)\n    {\n        _urlHelperFactory = urlHelperFactory;\n        _httpContextAccessor = httpContextAccessor;\n    }\n\n    public ValueTask<FluidValue> ProcessAsync(FluidValue input, FilterArguments arguments, LiquidTemplateContext context)\n    {\n        var urlHelper = _urlHelperFactory.GetUrlHelper(context.ViewContext);\n\n        var request = _httpContextAccessor.HttpContext?.Request\n            ?? throw new ArgumentException(\"HttpRequest missing while invoking 'switch_culture_url'\");\n\n        var targetCulture = input.ToStringValue();\n\n        var url = urlHelper.RouteUrl(\"RedirectToLocalizedContent\",\n            new\n            {\n                area = \"OrchardCore.ContentLocalization\",\n                targetCulture,\n                contentItemUrl = request.Path.Value,\n                queryStringValue = request.QueryString.Value,\n            });\n        return ValueTask.FromResult(FluidValue.Create(url, context.Options));\n    }\n}\n","sourceCodeStart":8,"sourceCodeEnd":41,"githubUrl":"https://github.com/OrchardCMS/OrchardCore/blob/4306c0717fe573f6fca1b4955909ddab6a192807/src/OrchardCore.Modules/OrchardCore.ContentLocalization/Liquid/SwitchCultureUrlFilter.cs#L8-L41","documentation":"The switch_culture_url Liquid filter builds a URL that redirects to the localized version of the current content. It needs the current HttpRequest to resolve the route; when HttpContext or its Request is unavailable (e.g. rendering a Liquid template outside an HTTP request) it throws ArgumentException.","triggerScenarios":"Using {{ content | switch_culture_url: 'fr' }} in a template rendered without a ViewContext/HttpContext — background email/liquid templating jobs, workflow activities without an HTTP context, or unit tests rendering templates directly.","commonSituations":"Sending Liquid-rendered notification emails from a background task; rendering templates in workflow scheduled events; running template previews in a console/hosted service.","solutions":["Only use switch_culture_url in templates rendered during an HTTP request.","In background flows, build the URL explicitly with IUrlHelper/LinkGenerator using a configured base URL instead of the filter.","Guard the template with an http-context availability check, or supply an IHttpContextAccessor-backed DefaultHttpContext.","Wrap rendering in try/catch and fall back to a plain culture-neutral link."],"exampleFix":"// before\nvar url = await template.RenderAsync(...); // template uses switch_culture_url, no HttpContext\n// after\nvar url = _linkGenerator.GetPathByRouteName(\"RedirectToLocalizedContent\", new { area = \"OrchardCore.ContentLocalization\", culture = \"fr\" });","handlingStrategy":"fallback","validationCode":"{% if http_context %}{{ content | switch_culture_url: 'fr' }}{% else %}/fr{{ content | display_text }}{% endif %}","typeGuard":"static bool HasRequest(LiquidTemplateContext ctx) => ctx.ViewContext?.HttpContext?.Request is not null;","tryCatchPattern":"try { url = await filter.ProcessAsync(input, args, ctx); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"switch_culture_url\"))\n{ url = fallbackPath; logger.LogDebug(\"switch_culture_url used outside HTTP context; using fallback\"); }","preventionTips":["Use HTTP-context-dependent filters only in request-scoped templates","In emails/background jobs, use LinkGenerator with an absolute base URL","Provide a DefaultHttpContext when unit-testing Liquid templates","Document which filters require an active request"],"tags":["liquid","contentlocalization","httpcontext"],"backgroundTag":"missing-dependency","analyzedSha":"4306c0717fe573f6fca1b4955909ddab6a192807","analyzedAt":"2026-09-13T17:41:05.024Z","contentChangedAt":"2026-09-13T17:41:05.024Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}