ytti/oxidized · error · OxidizedError

mechanize not found: sudo gem install mechanize

Error message

mechanize not found: sudo gem install mechanize

What it means

The HTTP input needs mechanize only when the node's model defines main_page together with a login callback (form-based login); connect then lazily requires 'mechanize' and converts LoadError into OxidizedError 'mechanize not found: sudo gem install mechanize' (lib/oxidized/input/http.rb:17-21). Without a login flow the input uses plain Net::HTTP and the gem is never required, so the error only appears for login-protected HTTP models.

Source

Thrown at lib/oxidized/input/http.rb:20

  require "net/http"
  require "json"
  require "net/http/digest_auth"

  class HTTP < Input
    def connect(node)
      @node = node
      @secure = false
      @username = nil
      @password = nil
      @headers = {}
      @node.model.cfg["http"].each { |cb| instance_exec(&cb) }

      return true unless @main_page && defined?(login)

      begin
        require "mechanize"
      rescue LoadError
        raise OxidizedError, "mechanize not found: sudo gem install mechanize"
      end

      @m = Mechanize.new
      url = URI::HTTP.build host: @node.ip, path: @main_page
      @m_page = @m.get(url.to_s)
      login
    end

    def cmd(callback_or_string)
      return cmd_cb callback_or_string if callback_or_string.is_a?(Proc)

      cmd_str callback_or_string
    end

    def cmd_cb(callback)
      instance_exec(&callback)
    end

View on GitHub (pinned to 687ed4262d)

Solutions

  1. Install the gem into the same Ruby oxidized runs with: sudo gem install mechanize (for distro packages, in the system gem home; for bundler, add gem 'mechanize' to the Gemfile and run bundle install)
  2. Verify with the service context: gem list mechanize and ruby -e "require 'mechanize'" using the same RUBY/GEM_HOME oxidized uses (check gem env)
  3. If the device needs no form login, remove main_page/login from the model so the plain Net::HTTP path runs without mechanize
  4. Rebuild docker images to include mechanize when any http model uses login

Example fix

# before (Gemfile)
gem 'oxidized'
# runtime: OxidizedError: mechanize not found: sudo gem install mechanize

# after (Gemfile)
gem 'oxidized'
gem 'mechanize'
# then: bundle install
Defensive patterns

Strategy: validation

Validate before calling

# fail fast at boot when any http model uses a login flow
begin
  gem 'mechanize'
rescue Gem::LoadError
  warn 'mechanize is missing: http input with login will raise OxidizedError'; exit 1
end

Type guard

def mechanize_available?
  require 'mechanize'
  true
rescue LoadError
  false
end

Try / catch

begin
  input.connect(node)
rescue OxidizedError => e
  logger.error "#{node.name}: #{e.message}"
  raise
end

Prevention

When it happens

Trigger: Setting input: http on a node whose model has main_page (e.g. main_page '/login.html') and a login block, while the mechanize gem is not installed in the Ruby/gemset that actually runs oxidized (distro package install, bundler project without the gem, or a container image missing it).

Common situations: Installing oxidized via apt/deb where mechanize is an optional extra; running under bundler with a Gemfile that omits mechanize; switching a device from ssh/telnet to http input with a login page; CI or docker images built before any http-login model was used.

Related errors


AI-assisted analysis of ytti/oxidized@687ed4262d (2026-08-23). Data as JSON: /api/errors/f5bc61e5283a5df6. Report an issue: GitHub.