This is a bug in the compiler that will be fixed in 4.12.0 and 4.11.2 once they are released (see #10010 for a detailed explanation).
One workaround is to separate the definition of the extension constructor from its first use with a dummy type definition:
type 'msg Vdom.Cmd.t +=
| Service of { on_ok: (string -> 'msg); on_error: (string -> 'msg) }
type workaround = |
let create_service ~on_ok ~on_error = Service { on_ok; on_error }