Ruby "can't modify frozen String" in CI - frozen_string_literal
A string literal is frozen - by a # frozen_string_literal: true magic comment or a newer Ruby default - and code tried to mutate it in place. The literal is immutable, so the in-place change raises FrozenError.
What this error means
Code that mutates a string (<<, gsub!, upcase!, []=) raises "FrozenError: can’t modify frozen String", often only on a file with the frozen_string_literal comment or under a newer Ruby. The same code ran on older Ruby without the comment.
app/lib/builder.rb:12:in `build': can't modify frozen String:
"prefix-" (FrozenError)
from app/lib/builder.rb:12:in `<main>'Common causes
frozen_string_literal makes literals immutable
The magic comment freezes every string literal in the file. In-place mutation of a literal (or a constant assigned a literal) then raises, where a non-frozen literal would have been modified.
Mutating a shared/constant string
A string assigned to a constant or returned from a frozen source is shared and frozen; mutating it in place is rejected.
How to fix it
Duplicate before mutating, or build a new string
Work on a mutable copy, or use non-mutating operations that return a new string.
s = (+"prefix-") # unary + gives a mutable copy
s << name
# or avoid in-place mutation
result = "prefix-" + nameBe deliberate about the magic comment
- Keep frozen_string_literal: true and fix the mutations - it is faster and safer.
- Use String#dup or unary + where a mutable buffer is genuinely needed.
- Run tests under the frozen-string default to catch mutations early.
How to prevent it
- Adopt frozen_string_literal: true and avoid mutating literals.
- Use +"" or dup for mutable string buffers.
- Test under the newer Ruby string defaults to catch FrozenError early.