urbanadventurer/WhatWeb · error

No target

Error message

No target

What it means

scan_from_plugin is the entry point plugins use to scan a target during WhatWeb's multi-threaded run. It raises 'No target' when the `target` keyword argument is nil or otherwise falsy, because there is nothing to open and scan. This is a fast-fail invariant check before target.open is attempted.

Solutions

  1. Always pass target: explicitly, e.g. scan_from_plugin(target: current_target)
  2. Guard before calling: only invoke scan_from_plugin when a valid Target object exists
  3. Do not treat the nil queue sentinels (used to stop workers) as real targets
  4. Backtrace the call site to find where the target variable was lost

Example fix

// before
scan_from_plugin(target: nil)
// after
scan_from_plugin(target: target) unless target.nil?
Defensive patterns

Strategy: type-guard

Validate before calling

scan_from_plugin(target: target) unless target.nil?

Type guard

def scannable_target?(t)
  !t.nil? && t.respond_to?(:open)
end

Try / catch

begin
  scan_from_plugin(target: t)
rescue RuntimeError => e
  raise unless e.message == 'No target'
  # skip or log: no target provided
end

Prevention

When it happens

Trigger: Calling WhatWeb::Scanner#scan_from_plugin with no target: keyword, or with target: nil — e.g. a plugin that passes an unset variable or an empty result from target-list construction.

Common situations: Plugin authors calling scan_from_plugin inside a passive/aggressive match block without wiring the current target through; race or logic bugs where the worker dequeued a nil sentinel (the queue is seeded with nils to shut workers down) and invoked the method with it.

Related errors


AI-assisted analysis of urbanadventurer/WhatWeb@d279d93042 (2026-09-15). Data as JSON: /api/errors/40654c6322ab7e1b. Report an issue: GitHub.

Appendix: source

Thrown at lib/whatweb/scan.rb:89

      # exit

      loop do
        # this might miss redirects from final targets

        # more defensive than comparing against max_threads
        alive = workers.map { |worker| worker if worker.alive? }.compact.length
        break if alive == @target_queue.num_waiting && @target_queue.empty?
      end

      # Shut down workers, logging, and plugins
      (1..@max_threads).each { @target_queue << nil }
      workers.each(&:join)
    end

    # for use by Plugins
    def scan_from_plugin(target: nil)
      raise 'No target' unless target

      begin
        target.open
      rescue => e
        error("ERROR Opening: #{target} - #{e}")
      end
      target
    end

    def add_target(url, redirect_counter = 0)
      # Normalize the URL for comparison
      normalized_url = normalize_url_for_comparison(url)
      
      # Check if this URL or a very similar one is already in the queue
      if already_queued_or_processed?(normalized_url)
        debug("Skipping duplicate target: #{url} (already queued or similar)")
        return
      end

View on GitHub (pinned to d279d93042)