{"record":{"id":"40654c6322ab7e1b","repo":"urbanadventurer/WhatWeb","slug":"no-target","errorCode":null,"errorMessage":"No target","messagePattern":"No target","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/whatweb/scan.rb","lineNumber":89,"sourceCode":"\n      # exit\n\n      loop do\n        # this might miss redirects from final targets\n\n        # more defensive than comparing against max_threads\n        alive = workers.map { |worker| worker if worker.alive? }.compact.length\n        break if alive == @target_queue.num_waiting && @target_queue.empty?\n      end\n\n      # Shut down workers, logging, and plugins\n      (1..@max_threads).each { @target_queue << nil }\n      workers.each(&:join)\n    end\n\n    # for use by Plugins\n    def scan_from_plugin(target: nil)\n      raise 'No target' unless target\n\n      begin\n        target.open\n      rescue => e\n        error(\"ERROR Opening: #{target} - #{e}\")\n      end\n      target\n    end\n\n    def add_target(url, redirect_counter = 0)\n      # Normalize the URL for comparison\n      normalized_url = normalize_url_for_comparison(url)\n      \n      # Check if this URL or a very similar one is already in the queue\n      if already_queued_or_processed?(normalized_url)\n        debug(\"Skipping duplicate target: #{url} (already queued or similar)\")\n        return\n      end","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/urbanadventurer/WhatWeb/blob/d279d93042d034f3fd29d5a893d44ccc0595d3f8/lib/whatweb/scan.rb#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always pass target: explicitly, e.g. scan_from_plugin(target: current_target)","Guard before calling: only invoke scan_from_plugin when a valid Target object exists","Do not treat the nil queue sentinels (used to stop workers) as real targets","Backtrace the call site to find where the target variable was lost"],"exampleFix":"// before\nscan_from_plugin(target: nil)\n// after\nscan_from_plugin(target: target) unless target.nil?","handlingStrategy":"type-guard","validationCode":"scan_from_plugin(target: target) unless target.nil?","typeGuard":"def scannable_target?(t)\n  !t.nil? && t.respond_to?(:open)\nend","tryCatchPattern":"begin\n  scan_from_plugin(target: t)\nrescue RuntimeError => e\n  raise unless e.message == 'No target'\n  # skip or log: no target provided\nend","preventionTips":["Always pass target: as an explicit keyword argument","Check target.respond_to?(:open) as a proxy for a valid Target","Never feed worker-queue nil sentinels into scan_from_plugin","Assert target presence in plugin match blocks"],"tags":["ruby","whatweb","plugin","nil-argument","scanner"],"backgroundTag":"null-argument","analyzedSha":"d279d93042d034f3fd29d5a893d44ccc0595d3f8","analyzedAt":"2026-09-15T13:51:42.453Z","contentChangedAt":"2026-09-15T13:51:42.453Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}