Grundsätzlich gilt:
Ist ein Teilergebnis eines Ausdruckes NULL, ist der gesamte Ausdruck NULL.
Nun meldet dir "to_Date" den Fehler, dass kein Datum in dem unteren Ausdruck steckt.
Nun muss also die tiefste Ebene den NULLIF enthalten:
...char(NULLIF(START_D, 0))...
Dies ergibt NULL für die CHAR-Funktion, die nun NULL liefert.
TO_DATE erhält nun ebenso NULL und liefert dann NULL als Ergebnis, so dass nun IFNULL das 2. Element liefern kann.
IFNULL entspricht der COALESCE-Funktion, mit der Ausnahme, dass nur 2 Argumente verwendet werden können.
NULLIF liefert NULL, wenn der Vergleich identisch ist. Ebenso aber auch, wenn ein Argument NULL ist.

Eine Funktion, die das gewünschte Ergebnis nicht bringen kann, wirft eine Exception aus, die den gesamten SQL abbricht. Ein Abfangen so ist nicht möglich.
Mittels NULLIF kann man aber einen Vergleich anstellen, der die Gültigkeit (eingeschränkt) prüfen kann.
NULLIF entspricht:
case when Feld is null then null else feld end
Und somit kann man hier ebenso andere Püfungen in einem Case-Ausdruck durchführen, die im Fehlerfall eben NULL, alternativ aber auch einen Default liefern können:

case when start_d = 0 then 19000101 else start_d end

Du sieht, es gibt viele Wege zum Erfolg.