discourse/discourse · error · Discourse::InvalidAccess

access denied

Error message

access denied

What it means

A guard in Search#initialize raising Discourse::InvalidAccess with the generic 'access denied' message when the search context or options (e.g. searching private messages, or an @user / search context the guardian may not inspect) imply access the acting user's Guardian does not grant. The at-fault input is the combination of search term/context/options supplied to Search.new.

Solutions

  1. Log in — several search contexts (PMs, user-scoped searches) require an authenticated guardian
  2. Remove the in:messages / private-messages filters or @user context unless you have permission to see them
  3. Check category security and can_see_private_messages? for the acting user
  4. Rescue Discourse::InvalidAccess and return an empty or 403 result rather than leaking visibility
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at lib/search.rb:283 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


AI-assisted analysis of discourse/discourse@1b2d7253e8 (2026-08-26). Data as JSON: /api/errors/d76d06ec42e94909. Report an issue: GitHub.

Appendix: source

Thrown at lib/search.rb:283

    term = process_advanced_search!(term)
    if !@order &&
         SiteSetting.search_default_sort_order !=
           SearchSortOrderSiteSetting.value_from_id(:relevance)
      @order = SearchSortOrderSiteSetting.id_from_value(SiteSetting.search_default_sort_order)
    end

    if term.present?
      @term = Search.prepare_data(term, Topic === @search_context ? :topic : nil)
      @original_term = Search.escape_string(@term)
    end

    if @search_pms || @search_all_pms || @opts[:type_filter] == "private_messages"
      @opts[:type_filter] = "private_messages"
      @search_context ||= @guardian.user

      unless @search_context.present? && @guardian.can_see_private_messages?(@search_context.id)
        raise Discourse::InvalidAccess.new
      end
    end

    @opts[:type_filter] = "all_topics" if @search_all_topics && @guardian.user

    @results =
      GroupedSearchResults.new(
        type_filter: @opts[:type_filter],
        term: clean_term,
        blurb_term: term,
        search_context: @search_context,
        blurb_length: @blurb_length,
        is_header_search: !use_full_page_limit,
        can_lazy_load_categories: @guardian.can_lazy_load_categories?,
      )
  end

  def limit

View on GitHub (pinned to 1b2d7253e8)