Skip to content

Commit 93aac61

Browse files
fix(alias): report the real reason for alias validation failures (#3111)
* fix(alias): report the real reason for alias validation failures Alias handlers routed failures through create_model_error(), which rewrites its message whenever the name is absent from the registry — always true for a new alias — so every validation error reported "model not found" plus a list of unrelated models instead of the actual cause. The CLI compounded this: extract_server_error_message() only unwrapped string-shaped error bodies, so object-shaped ones (what the server actually emits) printed only "Request failed: <code>". That affected every CLI command hitting a structured error, not just aliases. Also corrects the Muse Glimmer post, which promised built-in availability on a specific weekday and date; it now refers to the version instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(alias): classify internal alias failures as server errors create_alias_error() hardcoded invalid_request_error, so the three 500 paths reported a server-side failure as a client request error. Reported by fl0rianr in review. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 3e53259 commit 93aac61

3 files changed

Lines changed: 34 additions & 13 deletions

File tree

docs/news/muse-glimmer.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ <h3>Point llama.cpp at the latest release</h3>
536536

537537
<p class="mg-note"><strong>Note:</strong> Set the same key to <code>builtin</code> to return to the llama.cpp version Lemonade ships and tests, for example <code>lemonade config set llamacpp.vulkan_bin=builtin</code>.</p>
538538

539-
<p class="mg-note"><strong>Note:</strong> Muse Glimmer ships as a built-in model in the regular Wednesday Lemonade release on August 12, so this step becomes optional then.</p>
539+
<p class="mg-note"><strong>Note:</strong> Muse Glimmer ships as a built-in model in Lemonade v11.6.0, so this step becomes optional once you update.</p>
540540
</div>
541541
</div>
542542

src/cpp/cli/lemonade_client.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,15 @@ std::string extract_server_error_message(const HttpError& error) {
140140
if (!error.response_body().empty()) {
141141
try {
142142
auto parsed = json::parse(error.response_body());
143-
if (parsed.contains("error") && parsed["error"].is_string()) {
144-
return parsed["error"].get<std::string>();
143+
if (parsed.contains("error")) {
144+
const auto& err = parsed["error"];
145+
if (err.is_string()) {
146+
return err.get<std::string>();
147+
}
148+
// OpenAI-style bodies nest the text under error.message.
149+
if (err.is_object() && err.contains("message") && err["message"].is_string()) {
150+
return err["message"].get<std::string>();
151+
}
145152
}
146153
} catch (const json::exception&) {
147154
}

src/cpp/server/server.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5785,6 +5785,20 @@ void Server::handle_cleanup_cache(const httplib::Request& req, httplib::Response
57855785
}
57865786
}
57875787

5788+
// Alias failures are not model-lookup failures. create_model_error() rewrites its
5789+
// message whenever the name is absent from the registry, which is always true for a
5790+
// new alias, so routing these through it would report "model not found" instead of
5791+
// the actual reason.
5792+
static nlohmann::json create_alias_error(const std::string& message, const std::string& code,
5793+
const std::string& type = "invalid_request_error") {
5794+
return nlohmann::json{{"error", {
5795+
{"message", message},
5796+
{"type", type},
5797+
{"param", "alias"},
5798+
{"code", code}
5799+
}}};
5800+
}
5801+
57885802
void Server::handle_aliases_get(const httplib::Request& req, httplib::Response& res) {
57895803
try {
57905804
nlohmann::json alias_list = nlohmann::json::array();
@@ -5811,7 +5825,7 @@ void Server::handle_aliases_get(const httplib::Request& req, httplib::Response&
58115825
res.set_content(nlohmann::json{{"aliases", alias_list}}.dump(), "application/json");
58125826
} catch (const std::exception& e) {
58135827
res.status = 500;
5814-
res.set_content(create_model_error("", e.what()).dump(), "application/json");
5828+
res.set_content(create_alias_error(e.what(), "internal_error", "server_error").dump(), "application/json");
58155829
}
58165830
}
58175831

@@ -5823,41 +5837,41 @@ void Server::handle_aliases_add(const httplib::Request& req, httplib::Response&
58235837

58245838
if (alias.empty() || target.empty()) {
58255839
res.status = 400;
5826-
res.set_content(create_model_error("", "Alias and target fields are required").dump(), "application/json");
5840+
res.set_content(create_alias_error("Alias and target fields are required", "invalid_request").dump(), "application/json");
58275841
return;
58285842
}
58295843

58305844
if (alias == target) {
58315845
res.status = 400;
5832-
res.set_content(create_model_error(alias, "Alias cannot point to itself").dump(), "application/json");
5846+
res.set_content(create_alias_error("Alias cannot point to itself", "invalid_alias").dump(), "application/json");
58335847
return;
58345848
}
58355849

58365850
if (alias.rfind("user.", 0) == 0 || alias.rfind("extra.", 0) == 0 || alias.rfind("builtin.", 0) == 0) {
58375851
res.status = 400;
5838-
res.set_content(create_model_error(alias, "Alias name cannot use reserved prefixes (user., extra., builtin.)").dump(), "application/json");
5852+
res.set_content(create_alias_error("Alias name cannot use reserved prefixes (user., extra., builtin.)", "invalid_alias").dump(), "application/json");
58395853
return;
58405854
}
58415855

58425856
if (model_manager_->model_exists(alias)) {
58435857
std::string canonical = model_manager_->resolve_model_name(alias);
58445858
if (canonical == alias || canonical == "user." + alias || canonical == "builtin." + alias) {
58455859
res.status = 409;
5846-
res.set_content(create_model_error(alias, "Cannot create alias '" + alias + "': Name conflicts with an existing canonical model").dump(), "application/json");
5860+
res.set_content(create_alias_error("Cannot create alias '" + alias + "': Name conflicts with an existing canonical model", "alias_conflict").dump(), "application/json");
58475861
return;
58485862
}
58495863
}
58505864

58515865
if (!alias_manager_) {
58525866
res.status = 500;
5853-
res.set_content(create_model_error(alias, "AliasManager uninitialized").dump(), "application/json");
5867+
res.set_content(create_alias_error("AliasManager uninitialized", "internal_error", "server_error").dump(), "application/json");
58545868
return;
58555869
}
58565870

58575871
std::string err_msg;
58585872
if (!alias_manager_->set_alias(alias, target, err_msg)) {
58595873
res.status = 409;
5860-
res.set_content(create_model_error(alias, err_msg).dump(), "application/json");
5874+
res.set_content(create_alias_error(err_msg, "alias_conflict").dump(), "application/json");
58615875
return;
58625876
}
58635877

@@ -5869,7 +5883,7 @@ void Server::handle_aliases_add(const httplib::Request& req, httplib::Response&
58695883
res.set_content(response.dump(), "application/json");
58705884
} catch (const std::exception& e) {
58715885
res.status = 400;
5872-
res.set_content(create_model_error("", e.what()).dump(), "application/json");
5886+
res.set_content(create_alias_error(e.what(), "invalid_request").dump(), "application/json");
58735887
}
58745888
}
58755889

@@ -5878,7 +5892,7 @@ void Server::handle_aliases_remove(const httplib::Request& req, httplib::Respons
58785892
try {
58795893
if (!alias_manager_ || !alias_manager_->remove_alias(alias)) {
58805894
res.status = 404;
5881-
res.set_content(create_model_error(alias, "Alias not found: " + alias).dump(), "application/json");
5895+
res.set_content(create_alias_error("Alias not found: " + alias, "alias_not_found").dump(), "application/json");
58825896
return;
58835897
}
58845898
nlohmann::json response = {
@@ -5888,7 +5902,7 @@ void Server::handle_aliases_remove(const httplib::Request& req, httplib::Respons
58885902
res.set_content(response.dump(), "application/json");
58895903
} catch (const std::exception& e) {
58905904
res.status = 500;
5891-
res.set_content(create_model_error(alias, e.what()).dump(), "application/json");
5905+
res.set_content(create_alias_error(e.what(), "internal_error", "server_error").dump(), "application/json");
58925906
}
58935907
}
58945908

0 commit comments

Comments
 (0)