Can I prevent get_the_post_thumbnail from falling back to the global post ID?

As you are storing posts IDs in meta fields of another post (let’s call this post “the main post”), you can get that meta field and if it is empty, just avoid the use of get_the_post_thumbnail().

(For the next examples, I suppose that you are stroing one post ID in one meta field of the main post; if this is not the case, just say it and explain what data format you are using).

For example, if you are in the Loop of the main post:

while( have_posts() ) {
    the_post();

    // used inside the loop, get_the_ID() returns current post ID in the loop
    // replace meta_field_that_stores_post_ID with the key of your meta field
    // last param is set to true, so get_post_meta() retuns empty string if the meta field doesn't exists
    $thumb_post_ID = get_post_meta( get_the_ID(), 'meta_field_that_stores_post_ID', true );
    if( ! empty( $thumb_post_ID ) ) {
        echo get_the_post_thumbnail( $thumb_post_ID );
    }

}

You could separated that logic from the template, for example using a template tag:

function cyb_get_the_post_thumbnail() {

    $thumb_post_ID = get_post_meta( get_the_ID(), 'meta_field_that_stores_post_ID', true );

    if( ! empty( $thumb_post_ID ) {
        echo get_the_post_thumbnail( $thumb_post_ID );
    }
}

And then use cyb_get_the_post_thumbnail() wherever you need it within the loop of the main post.

If you are not within the loop of the main post, you need to know, at least, the ID of the main post and do something like this:

$thumb_post_ID = get_post_meta( 254, 'meta_field_that_stores_post_ID', true );
if( ! empty( $thumb_post_ID ) {
    echo get_the_post_thumbnail( $thumb_post_ID );
}