{"record":{"id":"d546efc2759beb88","repo":"sgl-project/sglang","slug":"unknown-match-type-param-match-type-must-b","errorCode":null,"errorMessage":"Unknown match_type: '${param_.match_type}'. Must be 'BFS' or 'PROB'.","messagePattern":"Unknown match_type: '(.+?)'\\. Must be 'BFS' or 'PROB'\\.","errorType":"exception","errorClass":"std::runtime_error","httpStatus":null,"severity":"error","filePath":"python/sglang/kernels/jit/csrc/ngram_corpus/ngram.cpp","lineNumber":166,"sourceCode":"  if (state_ids.size() != tokens.size() || state_ids.size() != total_lens.size()) {\n    throw std::runtime_error(\"batchMatch expects state_ids, tokens, and total_lens to match in size\");\n  }\n\n  std::unique_lock<std::mutex> lock(mutex_);\n\n  using TrieResultBuildFn =\n      Result (Trie::*)(const int32_t*, size_t, int32_t, size_t, const Param&, MatchState&, size_t) const;\n  using SamResultBuildFn = Result (SuffixAutomaton::*)(const int32_t*, size_t, int32_t, size_t, const Param&) const;\n  TrieResultBuildFn trie_result_build_fn;\n  SamResultBuildFn sam_result_build_fn;\n  if (param_.match_type == \"BFS\") {\n    trie_result_build_fn = &Trie::buildRecency;\n    sam_result_build_fn = &SuffixAutomaton::buildRecency;\n  } else if (param_.match_type == \"PROB\") {\n    trie_result_build_fn = &Trie::buildFrequency;\n    sam_result_build_fn = &SuffixAutomaton::buildFrequency;\n  } else {\n    throw std::runtime_error(\"Unknown match_type: '\" + param_.match_type + \"'. Must be 'BFS' or 'PROB'.\");\n  }\n\n  // All budget values are loop-invariant (mutex_ held, sams_ won't change).\n  const size_t num_sams = sams_.size();\n  const auto total_draft_token_num = param_.get_draft_token_num(tokens.size());\n  const size_t total_sam_budget =\n      num_sams > 0 ? std::min(param_.external_sam_budget, total_draft_token_num) : size_t{0};\n  const size_t per_sam_budget = num_sams > 0 ? total_sam_budget / num_sams : size_t{0};\n  const size_t trie_budget = total_draft_token_num - (per_sam_budget * num_sams);\n\n  Result merged;\n  for (size_t i = 0; i < state_ids.size(); ++i) {\n    const auto& suffix = tokens[i];\n    if (suffix.empty()) {\n      throw std::runtime_error(\"batchMatch received an empty token tail\");\n    }\n\n    auto& state = match_state_[state_ids[i]];","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/kernels/jit/csrc/ngram_corpus/ngram.cpp#L148-L184","documentation":"The matcher supports exactly two match strategies selected by param_.match_type: 'BFS' (recency-based buildRecency) and 'PROB' (frequency-based buildFrequency). Any other string is rejected at dispatch time inside batchMatch.","triggerScenarios":"Constructing/using Ngram with param.match_type set to anything other than \"BFS\" or \"PROB\" (e.g. \"bfs\" lowercase, \"probabilistic\", typo) and then calling batchMatch.","commonSituations":"Case mismatch from config strings ('bfs' vs 'BFS'); new/renamed strategy string after a version change; user-supplied config value passed through unvalidated.","solutions":["Set match_type to exactly \"BFS\" or \"PROB\"","Normalize/uppercase the config string before constructing Param","Validate match_type at config-parse time and fail fast with a clear message"],"exampleFix":"// before\nparam.match_type = \"bfs\"; // throws in batchMatch\n// after\nparam.match_type = \"BFS\";","handlingStrategy":"validation","validationCode":"if (param.match_type != \"BFS\" && param.match_type != \"PROB\") throw std::invalid_argument(\"match_type must be BFS or PROB\");","typeGuard":"bool match_type_valid(const std::string& s) { return s == \"BFS\" || s == \"PROB\"; }","tryCatchPattern":null,"preventionTips":["Uppercase-normalize match_type from user config","Fail fast at config parse, not inside batchMatch"],"tags":["ngram","config-validation","enum-value"],"backgroundTag":"invalid-enum-value","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}