capistrano/capistrano · error · NoMethodError
undefined method `execute' for main:Object
Error message
undefined method `execute' for main:Object
What it means
`execute` is an SSHKit method that runs a command on remote hosts through the backend established by Capistrano's `on(roles(...)) { ... }` scope. Outside an `on` block there is no backend, so Capistrano defines a top-level `execute` on the DSL purely to catch this beginner mistake: it prints a colored remediation hint to stderr (showing how to wrap the call in `on roles(:app)`) and then raises NoMethodError for main:Object. The error is intentional and the printed example above the exception is the actual fix.
Source
Thrown at lib/capistrano/dsl.rb:91
# rubocop:enable Security/MarshalLoad
def run_locally(&block)
SSHKit::Backend::Local.new(&block).run
end
# Catch common beginner mistake and give a helpful error message on stderr
def execute(*)
file, line, = caller.first.split(":")
colors = SSHKit::Color.new($stderr)
$stderr.puts colors.colorize("Warning: `execute' should be wrapped in an `on' scope in #{file}:#{line}.", :red)
$stderr.puts
$stderr.puts " task :example do"
$stderr.puts colors.colorize(" on roles(:app) do", :yellow)
$stderr.puts " execute 'whoami'"
$stderr.puts colors.colorize(" end", :yellow)
$stderr.puts " end"
$stderr.puts
raise NoMethodError, "undefined method `execute' for main:Object"
end
end
end
extend Capistrano::DSL
View on GitHub (pinned to b54b02fa0e)
Solutions
- Wrap the call in an `on` scope: `on roles(:app) do execute "whoami" end` (exactly as the stderr hint shows)
- For commands on the deploy machine itself, use `run_locally { execute "whoami" }` instead of `on`
- If the code lives in a helper, pass the backend explicitly or define the helper inside the `on` block so `execute` resolves against SSHKit::Backend
Example fix
# before
task :check do
execute "whoami" # NoMethodError: main:Object
end
# after
task :check do
on roles(:app) do
execute "whoami"
end
end Defensive patterns
Strategy: type-guard
Validate before calling
# assert a backend context exists before shelling out if defined?(SSHKit::Backend) && SSHKit::Backend.current.is_a?(SSHKit::Backend::ConnectionPool::NilClass) raise "execute called outside an `on` scope" end
Type guard
def inside_sshkit_backend?
respond_to?(:execute) && !is_a?(Object) # top-level main:Object stub means we are OUTSIDE `on`
end
# practical check: run within `on`/`run_locally` blocks only
within_backend = self.class.ancestors.any? { |a| a.name.to_s.start_with?("SSHKit::Backend") } Try / catch
begin
execute "whoami"
rescue NoMethodError => e
raise unless e.message.include?("execute' for main:Object")
run_locally { execute "whoami" } # or wrap in on roles(:app)
end Prevention
- Indentation discipline: any execute/capture/upload! line must sit inside an `on ... do` or `run_locally do` block
- Define shared remote helpers as methods that take the backend as self (define them inside the on block) or check `respond_to?(:backend)`
- Run `cap --dry-run` style smoke loads after refactors to hit the top-level stub early
When it happens
Trigger: Calling `execute "whoami"`, `capture`, or `sudo` (which calls execute) directly inside a `task ... do` block without an enclosing `on` block; calling execute in a helper method invoked outside any `on` scope; running code at file-load time in deploy.rb outside a task/on.
Common situations: First Capistrano 3 project (Capistrano 2 allowed top-level `run`); refactoring a task and accidentally moving a line out of the `on` block; defining shared helper methods that call execute and invoking them from the wrong nesting level.
Related errors
- #{name} reserved name for role. Please choose another name
- Both a block and an object were given
- Provided custom filter <#{filter.inspect}> does not have a p
- Value and block both passed to Configuration#set
- Task #{post_task.inspect} not found
AI-assisted analysis of capistrano/capistrano@b54b02fa0e (2026-08-21).
Data as JSON: /api/errors/ed1bdcb1a706163d.
Report an issue: GitHub.