discourse/discourse · error · Discourse::InvalidParameters

traffic_type

Error message

traffic_type

What it means

For the traffic_type dimension, normalize_filter_value coerces the item to a string and requires it to be in the TRAFFIC_TYPE_VALUES allowlist; anything else raises Discourse::InvalidParameters.new(:traffic_type). The allowlist is the fixed set of traffic classification buckets the explorer can query.

Source

Thrown at app/services/admin_dashboard_site_traffic_explorer.rb:73

      errors.add(:start_date, :invalid)
    end

    def normalize_filter(key, value)
      return nil if value.nil?

      raise Discourse::InvalidParameters.new(key) if value.empty? || value.size > DIMENSION_LIMIT

      value.map { |item| normalize_filter_value(key, item) }.uniq
    end

    def normalize_filter_value(key, value)
      return "" if key == :referrer && value == ""
      raise Discourse::InvalidParameters.new(key) if value.blank?

      case key
      when :traffic_type
        traffic_type = value.to_s
        raise Discourse::InvalidParameters.new(key) if !TRAFFIC_TYPE_VALUES.include?(traffic_type)
        traffic_type
      when :top_url, :entry_url
        BrowserPageviewEventUrlNormalizer.normalize_site_path(value) ||
          raise(Discourse::InvalidParameters.new(key))
      when :country
        country = value.to_s.upcase
        raise Discourse::InvalidParameters.new(key) if !country.match?(/\A[A-Z]{2}\z/)
        country
      when :network
        match = value.to_s.match(/\AAS(\d+)\z/)
        raise Discourse::InvalidParameters.new(key) if !match
        match[1].to_i
      when :browser
        browser = value.to_s
        raise Discourse::InvalidParameters.new(key) if !BROWSER_VALUES.include?(browser)
        browser
      when :ip
        IPAddr.new(value.to_s).to_s

View on GitHub (pinned to 1b2d7253e8)

Solutions

  1. Read TRAFFIC_TYPE_VALUES from the service class and drive the UI dropdown from it
  2. Send exactly the canonical strings (e.g. the values defined in AdminDashboardSiteTrafficExplorer::TRAFFIC_TYPE_VALUES)
  3. On error, fetch/refresh the allowlist rather than guessing

Example fix

# before
filters = {traffic_type: ["Organic"]}
# after
filters = {traffic_type: AdminDashboardSiteTrafficExplorer::TRAFFIC_TYPE_VALUES.first(1)
Defensive patterns

Strategy: type-guard

Validate before calling

values &= AdminDashboardSiteTrafficExplorer::TRAFFIC_TYPE_VALUES

Type guard

def valid_traffic_type?(v)
  AdminDashboardSiteTrafficExplorer::TRAFFIC_TYPE_VALUES.include?(v.to_s)
end

Try / catch

rescue Discourse::InvalidParameters => e
  render json: { errors: ["traffic_type must be one of the allowed values"] }, status: 400
end

Prevention

When it happens

Trigger: ?traffic_type=organic or ?traffic_type=email when those are not in TRAFFIC_TYPE_VALUES; sending a symbol-like raw value, wrong casing, or a pluralized label from a custom UI.

Common situations: Custom dashboards or scripts invent traffic type labels instead of using the API's canonical values; Discourse version changes alter the allowlist set; copy-paste from docs of a different version.

Related errors


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