Skip to content

install_cli fails under Rails: the CLI is written in text mode, as File::BINARY is a no-op outside Windows #177

Open

Description

@stephankaag

bin/rails claude_agent_sdk:install_cli, the Docker build step docs/rails.md suggests, fails in a Rails app:

ClaudeAgentSDK::CLIInstallError: Failed to fetch https://downloads.claude.ai/claude-code-releases/2.1.295/linux-arm64/claude:
Encoding::UndefinedConversionError: "\xB7" from ASCII-8BIT to UTF-8

The installer writes the download to a file opened with File::WRONLY | File::CREAT | File::EXCL | File::BINARY (lib/claude_agent_sdk/cli_installer.rb, line 184 on main 532cbdf). File::BINARY only matters on Windows; elsewhere it is 0, so the file is opened in text mode. Rails sets Encoding.default_internal to UTF-8, and a text-mode write then converts each binary chunk to UTF-8, which fails on the first byte that is not valid UTF-8.

Without Rails, the same happens as soon as default_internal is set, on main (1.4.0), on macOS here:

require "claude_agent_sdk"
require "tmpdir"

[nil, Encoding::UTF_8].each do |internal|
  Encoding.default_internal = internal
  Dir.mktmpdir do |dir|
    path = ClaudeAgentSDK::CLIInstaller.install_pinned(dir: dir)
    puts "#{internal.inspect}: installed #{File.size(path) / 1_000_000} MB"
  rescue ClaudeAgentSDK::CLIInstallError => e
    puts "#{internal.inspect}: #{e.message}"
  end
end
p File::BINARY
nil: installed 239 MB
#<Encoding:UTF-8>: Failed to fetch https://downloads.claude.ai/claude-code-releases/2.1.295/darwin-arm64/claude: Encoding::UndefinedConversionError: "\xCF" from ASCII-8BIT to UTF-8
0

Calling file.binmode right after the File.open (or opening with binmode: true) would make the write binary on every platform. Until then, a Dockerfile can install the CLI outside Rails:

RUN ruby -rbundler/setup -rclaude_agent_sdk -e 'ClaudeAgentSDK::CLIInstaller.install_pinned(dir: "vendor/claude")'

Found in a Rails 8.1 app, Ruby 4.0, claude-agent-sdk 1.3.0; the code is the same on main.

Activity

  1. ya-luotao commented on Oct 27, 2026

    @ya-luotao
    Collaborator

    Thanks for the report, and for pinning down the cause so precisely. The repro script made it a one-line fix.

    Fixed in #179 and released in 1.4.2 (now on rubygems.org). Http.download_to now opens the download with binmode: true, so the binary is written as-is whatever Encoding.default_internal is set to. A new spec writes non-UTF-8 bytes with default_internal = UTF-8 to keep it that way.

    With 1.4.2, bin/rails claude_agent_sdk:install_cli should work in the Docker build again, and the ruby -rbundler/setup ... workaround can go. I'll leave this open for now: could you confirm it works in your Rails 8.1 / Ruby 4.0 build?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions