Glad to help! Json can be a nightmare for small and inexplicable bugs. D:
I just dug through the ForgeBlockStateV1 code to understand why this happens. It's not specifically to do with the "custom" tag, it's just the way that forge identifies fully-defined variants. The way forge recognises a partially-defined variant (one where the properties will be combined with the properties from all other variants) is that the first element inside the variant is a json object (a tag followed by curly brackets). So the variant "property_name" is recognised as partially defined because the first element inside it is "one_value": { }, a json object:
"variants": {
"property_name": {
"one_value": {
// submodels and whatnot
},
"another_value": {
// submodels and whatnot
}
}
}
And a fully-defined variant which starts with, say, a "model" tag will be recognised because the first element inside it is not a json object (it's a json primitive, a tag and one string):
"variants": {
"full_variant": {
"model": "modid:modelname"
}
}
But, in a case like a fluid blockstates file, you might want to make a fully-defined variant (one that shouldn't be combined with other properties) where the first tag inside it happens to be a json object, like the "custom" tag:
"variants": {
"fluid_variant": {
"custom": {
// etc
}
}
}
So forge gets confused and thinks this is a property variant like the first example, and can't find it properly when it's needed. But (other than making sure the first element in the variant is an object, like by putting the "model" tag first inside every one), this check will be overriden if the variant is a json array (a tag followed by square brackets):
"variants": {
"fluid_variant": [{
"custom": {
// etc
}
}]
}
Sorry for the infodump, I got a bit focused on working this out because I've always been irritated by not understanding forge blockstates. I've seen advice to "use an array for fully-defined variants" but never quite understood why that was or how exactly it's defined.