---
title: "Constructors shouldn't throw"
slug: constructors-shouldnt-throw
url: https://listedarticles.com/articles/constructors-shouldnt-throw
canonical_url: https://t3.at/blog/2025-07-20-constructors-shouldnt-throw/
content_type: opinion
language: en
published_at: 2025-07-20T00:00:00.000Z
updated_at: 2026-10-19T11:15:22.418Z
author: "Florian (Flonk)"
authored_by: human
publisher: "T3 Blog"
publisher_url: https://t3.at/
topics: ["Programming", "Software Engineering", "Opinion"]
license: all-rights-reserved
word_count: 397
reading_minutes: 2
citation: "Florian (Flonk), T3 Blog. \"Constructors shouldn't throw.\" 20 Jul 2025. https://t3.at/blog/2025-07-20-constructors-shouldnt-throw/ (all-rights-reserved)"
# The full text follows. The web page shows an extract and sends readers
# to the source above; quote the citation and link the canonical URL.
---

# Constructors shouldn't throw

> A short opinion piece arguing constructors should never throw, do async work, or perform side effects; parsing, connecting, and validation belong in factory methods or explicit lifecycle methods so object construction stays simple and predictable.

# Constructors shouldn't throw

I mean this is nothing new but it bears repeating.

Constructors should not throw exceptions. Nor should they do
any asynchronous stuff, or really, perform any side effects at all.

## But my Date constructor needs to parse a string!

Okay I’m not in the business of writing Date libraries, but still,
if you need to parse a string, write a parser. And then write
a factory method `Date.parse(string)` that uses that parser and
calls a private constructor.

## But my Database constructor needs to connect to the database!

Hell it does. Turn your `Database` class into a state machine
with an `uninitialized` and a `connected` state.
Then have a `Database.connect()` method that transitions the state
from `uninitialized` to `connected`. Your unit tests will love it.

## But my service needs to perform an API request!

Good grief please don’t. A factory method will be your friend here,
you can do the fetch request in your factory and pass the value of
the resolved promise to the constructor.

## But my constructor needs to log something!

Okay that’s fine. I’m not that militant.

## Why are you militant at all?

The C++ core guidelines say that “default constructors” should not
throw — those are the ones that take no arguments. In the C++
context especially that makes sense because there we have RAII
and you really don’t want a simple declaration like `Foo foo;`
to throw an exception. If it does, you end up with half-constructed
objects and memory leaks and complicated cleanup. The C++
container classes assume `noexcept` constructors for this reason,
because creating a list of size 20 calls your constructor 20 times,
and the cleanup gets so much messier.

We don’t have to worry about this in JavaScript at all, but I think
even there it’s good practice to avoid throwing exceptions in not
just no-arg constructors, but all of them.

Because the semantics of a constructor is to bring an object
into a valid state and you don’t expect it to perform any
functionality. Constructors should be simple and predictable.

Often your objects are constructed in completely different
places than where they are used so you really don’t want to
know about or deal with the implementation details of every class
at construction time. It’s a separation of concerns thing.

If your objects have a complicated lifecycle you should design
their APIs to reflect that.
