In what circumstances would a block appear in the Leveldb .ldb index but have no data in a .dat file? I've observed this behavior with Bitcoin Core v0.15 while parsing the LevelDB index in .bitcoin/blocks/index. It is also a situation that is obviously accounted for in the Bitcoin Core source code here (See BLOCK_HAVE_DATA and BLOCK_HAVE_UNDO). I am just looking to understand what would cause this to happen? Can a peer receive the block header before receiving the block itself? I'm finding that only the top few blocks in the chain seem to be missing data; They appear in the index but not the .dat files.
Bitcoin Core may only have just the block headers for some blocks, not the full block data. Such block headers would get an entry into the chainstate and block index as a block that the node knows about. However the node does not have the full block data corresponding to that header so there is no corresponding block data in the blk*.dat files.

This situation happens during syncing (since Bitcoin Core will fetch block headers first and then the blocks), when there are orphan blocks, and when there are chain forks.