Choose how an Active Storage attachment failure reaches its caller
Active Storage's attach! makes a failed save explicit. Choose checked results or exceptions deliberately, while keeping storage durability a separate concern.
A failed attachment save needs to reach the code that decides what happens next. An interface can make that failure available through a result that the caller checks or through an exception that interrupts the normal path. Either approach needs an owner. Continuing as though the attachment was saved because nobody checked is a broken application contract.
Rails' 16 May 2026 development summary introduced attach! as the bang counterpart to attach, raising an exception if the attachment was not saved. The public pull request shows a proposal opened on 31 January 2025 and merged into main on 14 May 2026. May was the merge, rather than the beginning of the proposal. Neither page establishes availability in an application's installed stable version.
The interesting choice is at the call site: is failure an expected outcome to present to someone, or a condition that invalidates the rest of the operation? The exclamation mark makes that question harder to ignore. It does not answer it for every workflow.
A result still needs to be read
Imagine a form where a person submits a document with its supporting file. This is an illustrative workflow, not a client project. If the application cannot save the attachment, the person needs a response consistent with what actually happened. A success screen that implies the complete submission exists would be misleading.
A checked result can make that branch explicit. The caller examines the outcome, retains the information needed to correct the form and explains the problem. This can be clearer when validation failures are part of normal use. Choosing ordinary attach is reasonable when the surrounding code takes responsibility for checking the relevant persistence outcome.
The weakness is easy to describe: a return path that nobody examines does not influence the application's next decision. A reviewer should be able to follow the failure from the attachment operation to a response or a recorded unresolved state. The presence of a method call alone proves no such handling.
Avoid treating the ordinary and bang methods as a hierarchy of developer maturity. They express different control-flow choices. A deliberate result check is stronger than an exception swallowed by a broad handler that still reports success.
An exception defines an interruption
A workflow can instead require the attachment save before anything that depends on it proceeds. In that case, an exception can express the prerequisite directly. The code calling the operation must know where that exception will be handled and which later actions it prevents.
Consider an illustrative background task that prepares a document for another step. If a missing attachment means that the next step cannot produce a valid result, stopping at the failed save may fit the task better than carrying a failure value through several unrelated calls. This is a design argument, not a claim about any job queue's retry behavior.
The handler still needs a policy. Retrying an operation may be appropriate for one cause and useless for another. Reporting the failure without enough context can leave the operator unable to decide. Raising an exception makes failure visible to the program; useful handling makes it intelligible to the person responsible.
This is also why a broad rescue deserves scrutiny. If it catches an attachment failure and continues into the success path, the stronger method has not preserved the application's prerequisite. The review should follow the control flow through the handler, rather than ending at attach!.
Save failure and storage durability are different claims
The cited change concerns the contract for an attachment that was not saved. It does not establish that an external storage service will retain an object indefinitely. It also does not make an external upload atomic with every database change in a larger business operation.
Those distinctions matter when the surrounding workflow spans several systems. An application may need to explain which state is authoritative, how incomplete work is represented and who resolves it. An exception mechanism can participate in that design, but its existence is insufficient evidence that the whole operation has one indivisible outcome.
The same restraint applies to user-facing wording. A message about a saved attachment should describe the state the application can establish. A broader promise about receipt, processing or long-term retention needs its own evidence. Otherwise a local method contract becomes an unsupported service guarantee.
Choose the contract at the boundary
Start a review by locating the decision made immediately after attachment persistence. If expected validation failures need to be shown in a form, a checked outcome may keep the behavior close to the reader's task. If successful persistence is a genuine prerequisite for later actions, the exception path may state that requirement more clearly.
Then inspect the opposite branch. What will the user or operator see? Which actions are still allowed? Where is the unresolved state recorded? These questions are useful without pretending that every failure shares a cause or that every exception merits an automatic retry.
Adoption also needs version evidence. A merged pull request is a historical development fact. Before changing application code, establish whether the deployed dependency includes the method and its relevant behavior. This article contains no upload execution or application test and does not assert that any particular installation supports it.
For custom software development, the useful specification is a short account of success, failure and responsibility at this boundary. Choose attach with checked handling where that fits, or attach! where interruption expresses the prerequisite. In both cases, a failed save must influence what the application does next.
Paul