Тест показал утечку, и утекло на пути, который завершился успешно. Функция выделяла временный буфер, разбирала данные в результат, которым владеет вызывающий, и освобождала временный буфер через errdefer allocator.free(scratch). Все ветки с ошибкой его освобождали. Успешный возврат - нет, и std.testing.allocator сообщил об утечке в конце теста.
Справочник здесь точен. errdefer выполняет выражение при выходе из блока тогда и только тогда, когда функция вернула ошибку. Обычный возврат возвратом ошибки не считается.
errdefer подходит для другого случая - для буфера, который после успеха принадлежит вызывающему и освобождается только при неудаче. Временный буфер принадлежит функции на любом пути. Это defer.
Выходит, ключевое слово фиксирует, кто владеет выделенной памятью после успешного возврата. errdefer говорит, что вызывающий. defer говорит, что никто вне функции. Выбор между ними сводится к решению о владении, а не вопрос стиля очистки. В C тот же выбор спрятан в том, какую метку успешный путь перепрыгивает в блоке очистки с goto.