Skip to content
can't modify frozen ...

can't modify frozen ...

DodaTech 3 min read

Ruby’s can't modify frozen error (a FrozenError) fires when you try to mutate an object frozen with .freeze — Ruby prevents all changes to frozen objects.

What It Means

Calling .freeze on an object makes it immutable — you can’t change its instance variables, replace its contents (for collections), or call mutating methods on it. This is a protection mechanism: frozen objects are safe to share across threads and can’t be accidentally modified. When you try to << a string, []= a hash element, or call any mutating method on a frozen object, Ruby raises FrozenError: can't modify frozen ....

Why It Happens

  • You explicitly called .freeze on an object earlier in the code.
  • A gem or framework freezes configuration objects or strings after initialization.
  • You’re trying to modify a string literal in-place — string literals are frozen by default with the # frozen_string_literal: true pragma.
  • A Hash or Array is frozen and you’re trying to add or remove elements.
  • self is frozen in a particular context (e.g., inside a frozen object’s method).

How to Fix It

Step 1: Find where the object was frozen

Search your codebase for .freeze calls on the object:

# If you see this:
CONFIG = {timeout: 30}.freeze

# Then this will fail:
CONFIG[:timeout] = 60  # FrozenError

Step 2: Duplicate the object before modification

Use .dup to create a mutable copy:

frozen_string = "hello".freeze
# frozen_string << " world"       # FrozenError

mutable_string = frozen_string.dup
mutable_string << " world"        # Works
puts mutable_string               # => "hello world"

Step 3: Remove the freeze call

If you control the code and freezing isn’t needed:

# Before
OPTIONS = {debug: true}.freeze

# After
OPTIONS = {debug: true}

Step 4: Handle frozen string literals

If your file has # frozen_string_literal: true at the top:

# frozen_string_literal: true

name = "Alice"
# name << " Smith"  # FrozenError — string literals are frozen

# Fix: use += instead of <<
name = name + " Smith"

# Or use .dup
name = "Alice".dup << " Smith"

Step 5: Check for frozen configuration objects in frameworks

Rails and other frameworks often freeze config after initialization:

# In config/initializers/some_file.rb
Rails.application.config.some_setting = "value"
# This config object is frozen after initialization
# If you try to modify it later, you'll get FrozenError

Step 6: Use non-mutating methods instead

frozen_array = [1, 2, 3].freeze
# frozen_array << 4                # FrozenError
new_array = frozen_array + [4]     # Works — creates a new array

frozen_string = "hello".freeze
# frozen_string.upcase!            # FrozenError
upcased = frozen_string.upcase     # Works — returns a new string
What is the difference between .dup and .clone on frozen objects?
Both create copies, but .clone preserves the frozen state of the original — the clone is also frozen. .dup always creates a mutable (unfrozen) copy. Use .dup when you need to modify the copy. Use .clone when you want the copy to maintain the same frozen state as the original.
Can I unfreeze an object in Ruby?
No — Ruby provides no built-in method to unfreeze an object. Freezing is irreversible by design. If you need to modify a frozen object, you must create a mutable copy with .dup and work with that instead. The only exception is using low-level C extensions or ObjectSpace hacks, which are not recommended.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro