         hmm_reference_window.x = reference_window_clipped.x - left_insertion - offset;
         hmm_reference_window.y = reference_window_clipped.y + right_insertion + offset;
 
+        // figure out if the HMM window is contained inside the chromosome this read is aligned to
+        auto& reference = ctx.reference_db.get_chromosome(batch.chromosome[read_index]);
+
+        int left_window_shift = 0;
+        if (hmm_reference_window.x < 0 && batch.alignment_start[read_index] < abs(hmm_reference_window.x))
+        {
+            // this is very likely a problem in GATK: because their reference and read coordinates are off by 1, they end up
+            // subtracting one base from the reference window when the start position is clamped
+            left_window_shift = -1;
+        }
+
+        if (read_needs_baq && batch.alignment_start[read_index] + hmm_reference_window.y + left_window_shift >= reference.bases.size())
+        {
+            // HMM window lies beyond the end of the reference sequence
+            // can't compute BAQ, filter out this read
+
+            // clear the cigar event -> read bp offset mapping for this read
+            const uint32 cigar_ev_start = ctx.cigar.cigar_offsets[idx.cigar_start];
+            const uint32 cigar_ev_stop = ctx.cigar.cigar_offsets[idx.cigar_start + idx.cigar_len];
+
+            for(uint32 i = cigar_ev_start; i < cigar_ev_stop; i++)
+            {
+                ctx.cigar.cigar_event_read_index[i] = uint32(-1);
+                ctx.cigar.cigar_event_read_coordinates[i] = uint16(-1);
+            }
+
+            // emit an invalid HMM window
+            // this will cause this read to be removed from the active read list
+            ctx.baq.hmm_reference_windows[read_index] = make_short2(short(-1), short(-1));
+
+            return;
+        }
+
         // write out the result
         ctx.baq.hmm_reference_windows[read_index] = hmm_reference_window;
 

    baq.hmm_reference_windows.resize(batch.device.num_reads);
    baq.bandwidth.resize(batch.device.num_reads);

    // compute the alignment frames
    // note: this is used both for real BAQ and flat BAQ, so we use the full active read list
    parallel<system>::for_each(context.active_read_list.begin(),
                               context.active_read_list.end(),
                               compute_hmm_windows<system>(context, batch.device));

#if ENABLE_LMEM_PATH
    if (!baq_use_lmem)

    struct baq_context<system>& baq = context.baq;
    vector<system, uint32>& active_baq_read_list = context.temp_u32;
    vector<system, uint32>& baq_state = context.temp_u32_2;
    vector<system, uint32>& temp_active_list = context.temp_u32_3;

    // check if we can use the lmem kernel
#if ENABLE_LMEM_PATH
