LTSpice: How can I specify a constant-dependent delay?
The delay can't be zero valued, so when dly &gt; 0 it works just fine. But the whole if() expression needs to be parsed prior to simulation, and when dly = 0, the delay() function is parsed and dly is replaced by its evaluated number, which is zero, and which gives a rightful error.
To solve this, make a second variable and replace dly inside the behavioural source:
.param dly=0 dly2=if(dly, dly, 1)
V=if(dly, delay(V(in), dly2), V(in))

This way, when dly == 0, dly2 will evaluate to something greater than 0. That branch will not be executed, but the evaluation will not result in an error.

Given the way the discussion went in the comments I don't know whether my English is to blame or you don't read my answer, but I'll give it another try.
Your original expression had a conditional, if(), and a delay(). The way the parser works is it first reads the whole expression and tries to make sense of it. The delay() function, as you had it written, was a function of dly which could be set to zero. Even if the condition would result in the other branch being executed, the parser still sees the whole expression and the fact that dly evaluates to zero in a delay() function. And since delay() needs an argument for delay that is positive definite, the parser finds this an error and aborts the simulation.
The solution that I proposed was to use a proxy for dly, named dly2, which has its own conditional to determine whether dly is positive definite or not and, if it is, to use its value, otherwise to use some other value -- it doesn't matter what value as long as it evaluates to a positive definite one. This way, when dly == 0, the parser finds the delay() function to have an argument that doesn't result in an error. The reason I chose 1, or the reason why your choice, 1e6, worked just as well, was because when dly2 evaluates to that, dly == 0, and the other branch of the if() is executed.
if( dly &gt; 0)
    delay()
else       // &lt;-- this branch is executed when dly == 0
    normal

Remember, dly2 is there to avoid a zero-valued delay, that's all. It doesn't matter if it's 1n, or 1meg, when dly == 0 it makes dly2 &gt; 0 and delay() is not the one that is executed. So it has nothing to do with .asy, or .param statments, it's just a trick to get around the zero delay problem. That's all.