Should a macro throw an error, or return expression that throws an error?

If the error can be thrown at compile-time, I’d say it’s best to fail during macro expansion. Examples of early macro expansion failure include the Test macros themselves:

julia> using Test

julia> @macroexpand @test true unsupported_kwarg=nothing
ERROR: invalid test macro call: @test true unsupported_kwarg = nothing

This example also illustrates how @macroexpand allows to clearly separate the macro expansion stage from the runtime, which allows testing for errors that happen during macro expansion:

julia> macro A()
           error("ko")
       end
@A (macro with 1 method)

julia> @test_throws ErrorException @macroexpand @A
Test Passed
      Thrown: ErrorException
3 Likes