dont call `on_close` directly