{"record":{"id":"7b037ebd89cedfbc","repo":"basecamp/kamal","slug":"raw-is-not-compatible-with-interactive","errorCode":null,"errorMessage":"Raw is not compatible with interactive","messagePattern":"Raw is not compatible with interactive","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/kamal/cli/accessory.rb","lineNumber":154,"sourceCode":"    if name == \"all\"\n      KAMAL.accessory_names.each { |accessory_name| details(accessory_name) }\n    else\n      type = \"Accessory #{name}\"\n      with_accessory(name) do |accessory, hosts|\n        on(hosts) { puts_by_host host, capture_with_info(*accessory.info), type: type, quiet: quiet }\n      end\n    end\n  end\n\n  desc \"exec [NAME] [CMD...]\", \"Execute a custom command on servers within the accessory container (use --help to show options)\"\n  option :interactive, aliases: \"-i\", type: :boolean, default: false, desc: \"Execute command over ssh for an interactive shell (use for console/bash)\"\n  option :reuse, type: :boolean, default: false, desc: \"Reuse currently running container instead of starting a new one\"\n  option :raw, type: :boolean, default: false, desc: \"Output raw, unmodified stdout\"\n  def exec(name, *cmd)\n    raw = options[:raw]\n\n    if raw && options[:interactive]\n      raise ArgumentError, \"Raw is not compatible with interactive\"\n    end\n\n    with_raw_output(raw) do\n      pre_connect_if_required\n\n      cmd = Kamal::Utils.join_commands(cmd)\n      quiet = options[:quiet]\n\n      with_accessory(name) do |accessory, hosts|\n        case\n        when options[:interactive] && options[:reuse]\n          say \"Launching interactive command via SSH from existing container...\", :magenta\n          run_locally { exec accessory.execute_in_existing_container_over_ssh(cmd) }\n\n        when options[:interactive]\n          say \"Launching interactive command via SSH from new container...\", :magenta\n          on(accessory.hosts.first) { execute *KAMAL.registry.login }\n          run_locally { exec accessory.execute_in_new_container_over_ssh(cmd) }","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/cli/accessory.rb#L136-L172","documentation":"`kamal accessory exec NAME CMD` runs a command inside an accessory's container. The --raw flag makes Kamal print the command's stdout unmodified (for scripting/piping), while -i/--interactive attaches an interactive SSH session for shells like bash/console. These modes are mutually exclusive because raw output capture cannot coexist with a TTY-attached interactive session, so Kamal raises ArgumentError before connecting to any host.","triggerScenarios":"Running `kamal accessory exec mysql --raw -i bash`, or any invocation where both options[:raw] and options[:interactive] are truthy, e.g. flags set in a shell alias or a script that always passes -i. Raised immediately in the exec method, before with_raw_output and before any SSH connection.","commonSituations":"Copy-pasting a console command from docs that uses -i while a wrapper script adds --raw to strip Kamal's log noise; aliases like `alias mysql-console='kamal accessory exec mysql -i --raw'`; piping output (`--raw`) while forgetting to remove -i from a previous command line.","solutions":["Drop one of the two flags: use `kamal accessory exec NAME -i bash` for a shell, or `kamal accessory exec NAME --raw CMD` for clean pipeable output.","If you need to capture output of an interactive-only program, run it non-interactively without -i and keep --raw.","Check shell aliases/scripts that inject flags automatically and remove the conflicting one."],"exampleFix":"# before\nkamal accessory exec mysql --raw -i bash\n# after\nkamal accessory exec mysql -i bash\n# or, for scriptable output:\nkamal accessory exec mysql --raw mysqladmin ping","handlingStrategy":"validation","validationCode":"raw = ARGV.include?(\"--raw\")\ninteractive = ARGV.include?(\"-i\") || ARGV.include?(\"--interactive\")\nabort \"--raw and -i are mutually exclusive\" if raw && interactive\n# then invoke: kamal accessory exec #{ARGV.join(' ')}","typeGuard":null,"tryCatchPattern":"begin\n  # programmatic invocation\n  Kamal::CLI::Accessory.new.invoke(:exec, [ \"mysql\", \"mysqladmin\", \"ping\" ], raw: true)\nrescue ArgumentError => e\n  raise unless e.message.include?(\"not compatible\")\n  warn \"flag conflict: #{e.message}\" # strip -i or --raw and retry once\nend","preventionTips":["Decide per task: interactive shell (-i) or machine-readable output (--raw), never both.","Keep kamal invocations in scripts flag-minimal; add flags per call rather than in a shared alias.","Add a preflight arg check in wrappers that reject conflicting flags before calling kamal."],"tags":["kamal","accessory","exec","cli","argument-conflict"],"backgroundTag":"mutually-exclusive-flags","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}