Skip to content

Commit bc549da

Browse files
authored
server : catch sampler/grammar exceptions to avoid process abort (#1725) (#1726)
Wrap the two slot-level sample/accept call sites in try/catch (std::exception). On exception: log, send_error to the task, release the slot, continue serving. Matches the existing try/catch around common_sampler_init in the same file. Without this, llama_grammar_accept_token throwing "Unexpected empty grammar stack after accepting piece: <pad> (0)" (reproducible on Gemma 4 + json_schema + ctx_shift, see #1725) unwinds out of update_slots -> queue start_loop -> main, hits std::terminate, and aborts the whole server process.
1 parent e767001 commit bc549da

1 file changed

Lines changed: 31 additions & 4 deletions

File tree

examples/server/server-context.cpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3810,7 +3810,22 @@ void server_context::speculative_decoding_accept() {
38103810
apply_server_biases(slot);
38113811

38123812
// the accepted tokens from the speculation
3813-
const auto ids = common_sampler_sample_and_accept_n(slot.ctx_sampling, ctx, slot.i_batch_dft, slot.drafted);
3813+
std::vector<llama_token> ids;
3814+
try {
3815+
ids = common_sampler_sample_and_accept_n(slot.ctx_sampling, ctx, slot.i_batch_dft, slot.drafted);
3816+
} catch (const std::exception & e) {
3817+
LOG_ERROR("speculative sampling failed, releasing slot", {
3818+
{"id_slot", slot.id},
3819+
{"id_task", slot.id_task},
3820+
{"error", e.what()},
3821+
});
3822+
send_error(slot, std::string("sampling error: ") + e.what(), ERROR_TYPE_SERVER);
3823+
slot.release();
3824+
slot.i_batch = -1;
3825+
slot.i_batch_dft.clear();
3826+
slot.drafted.clear();
3827+
continue;
3828+
}
38143829

38153830
int32_t mtp_n_past_base = 0;
38163831
std::vector<float> mtp_hidden_state_pre;
@@ -4320,9 +4335,21 @@ void server_context::process_batch_tokens(int32_t & n_batch) {
43204335

43214336
apply_server_biases(slot);
43224337

4323-
const llama_token id = common_sampler_sample(slot.ctx_sampling, ctx, tok_idx);
4324-
4325-
common_sampler_accept(slot.ctx_sampling, ctx, id, true);
4338+
llama_token id;
4339+
try {
4340+
id = common_sampler_sample(slot.ctx_sampling, ctx, tok_idx);
4341+
common_sampler_accept(slot.ctx_sampling, ctx, id, true);
4342+
} catch (const std::exception & e) {
4343+
LOG_ERROR("sampling failed, releasing slot", {
4344+
{"id_slot", slot.id},
4345+
{"id_task", slot.id_task},
4346+
{"error", e.what()},
4347+
});
4348+
send_error(slot, std::string("sampling error: ") + e.what(), ERROR_TYPE_SERVER);
4349+
slot.release();
4350+
slot.i_batch = -1;
4351+
continue;
4352+
}
43264353

43274354
slot.n_decoded += 1;
43284355
const int64_t t_current = ggml_time_us();

0 commit comments

Comments
 (0)