Were you ever able to sort this out? I'm having the same issue. Best I can tell, somewhere after the save_post fires the $_POST data for that post/form gets trashed.
fwiw, what I'm considering doing is doing my validation and then using a post_meta as a proxy for $_POST. In other words, if validation fails write my form data to some post_meta. And whenever I'm displaying that form, I always first check for "error data".
To me this feel dirty and "hacky" but I'm also pretty sure it would work. After all, what is $_POST but an array. I don't think I want to store the whole $_POST in a post_meta, just the stuff I need for that form. And after all, that's where the form data is going to end up anyway...in post_meta.
Actually, now that I think about it, it might just be a matter of storing the validation error msg in post_meta and making sure a post isn't published unless the post_meta for error is blank. In other words, ! errors == OK to publish. Errors == Don't allow publish.
Storing "bad data" is fine. WP seems to be handling the storing just fine :) The real issue is error msgs AND preventing posts with "bad data" from being published.
What do you think?
FYI - This approach does in fact work, at least for custom post types and simple-ish forms. (It might work for more robust things but I'm kinda in proof of concept mode.)
The only thing I have to resolve is that WP will display "Post Published" (at the top of the page in a yellow box) even though I've bumped the post_status back to draft when the validation method(s) hit something that doesn't pass.
I'm pretty sure there's a way to suppress that, but I haven't looked into it just yet.