Add columns info in errors

This commit is contained in:
Mubelotix
2025-08-01 14:53:41 +02:00
parent 8fe4d33b5a
commit a20f353054
2 changed files with 51 additions and 31 deletions

View File

@ -202,6 +202,18 @@ use RenderError::*;
impl From<RenderError<'_>> for ResponseError {
fn from(error: RenderError) -> Self {
fn format_span(span: &Span<'_>) -> String {
let base_column = span.get_utf8_column();
let size = span.fragment().chars().count();
format!("`{}` (cols {}:{})", span.fragment(), base_column, base_column + size)
}
fn format_token(token: &Token<'_>) -> String {
let base_column = token.original_span().get_utf8_column();
let size = token.original_span().fragment().chars().count();
format!("`{}` (cols {}:{})", token.value(), base_column, base_column + size)
}
match error {
MultipleTemplates => ResponseError::from_msg(
String::from("Cannot provide both an inline template and a template ID."),
@ -216,7 +228,7 @@ impl From<RenderError<'_>> for ResponseError {
Code::InvalidRenderTemplateId,
),
UnknownTemplateRoot(root) => ResponseError::from_msg(
format!("Template ID must start with `embedders` or `chatCompletions`, but found `{root}`."),
format!("Template ID must start with `embedders` or `chatCompletions`, but found {}.", format_token(&root)),
Code::InvalidRenderTemplateId,
),
MissingEmbedderName { mut available } => {
@ -230,26 +242,29 @@ impl From<RenderError<'_>> for ResponseError {
EmbedderDoesNotExist { embedder, mut available } => {
available.sort_unstable();
ResponseError::from_msg(
format!("Embedder `{embedder}` does not exist.\n Hint: Available embedders are {}.",
format!("Embedder {} does not exist.\n Hint: Available embedders are {}.",
format_token(&embedder),
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId,
)
},
EmbedderUsesFragments { embedder } => ResponseError::from_msg(
format!("Requested document template for embedder `{embedder}` but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead."),
format!("Requested document template for embedder {} but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead.", format_token(&embedder)),
Code::InvalidRenderTemplateId,
),
MissingTemplateAfterEmbedder { embedder, mut indexing, mut search } => {
if indexing.is_empty() && search.is_empty() {
ResponseError::from_msg(
format!("Missing template id after embedder `{embedder}`.\n Hint: Available template: `documentTemplate`."),
format!("Missing template id after embedder {}.\n Hint: Available template: `documentTemplate`.",
format_token(&embedder)),
Code::InvalidRenderTemplateId,
)
} else {
indexing.sort_unstable();
search.sort_unstable();
ResponseError::from_msg(
format!("Template ID configured with `embedders.{embedder}` but no template kind provided.\n Hint: Available fragments are {}.",
format!("Template ID configured with embedder {} but no template kind provided.\n Hint: Available fragments are {}.",
format_token(&embedder),
indexing.iter().map(|s| format!("`indexingFragments.{s}`")).chain(
search.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId,
@ -259,14 +274,16 @@ impl From<RenderError<'_>> for ResponseError {
UnknownTemplatePrefix { embedder, found, mut indexing, mut search } => {
if indexing.is_empty() && search.is_empty() {
ResponseError::from_msg(
format!("Wrong template `{found}` after embedder `{embedder}`.\n Hint: Available template: `documentTemplate`."),
format!("Wrong template {} after embedder {}.\n Hint: Available template: `documentTemplate`.", format_token(&found), format_token(&embedder)),
Code::InvalidRenderTemplateId,
)
} else {
indexing.sort_unstable();
search.sort_unstable();
ResponseError::from_msg(
format!("Wrong template `{found}` after embedder `{embedder}`.\n Hint: Available fragments are {}.",
format!("Wrong template {} after embedder {}.\n Hint: Available fragments are {}.",
format_token(&found),
format_token(&embedder),
indexing.iter().map(|s| format!("`indexingFragments.{s}`")).chain(
search.iter().map(|s| format!("`searchFragments.{s}`"))).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId,
@ -277,9 +294,10 @@ impl From<RenderError<'_>> for ResponseError {
MissingFragment { embedder, kind, mut available } => {
available.sort_unstable();
ResponseError::from_msg(
format!("{} fragment name was not provided.\n Hint: Available {} fragments for embedder `{embedder}` are {}.",
format!("{} fragment name was not provided.\n Hint: Available {} fragments for embedder {} are {}.",
kind.capitalized(),
kind.as_str(),
format_token(&embedder),
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId,
)
@ -287,15 +305,17 @@ impl From<RenderError<'_>> for ResponseError {
FragmentDoesNotExist { embedder, fragment, kind, mut available } => {
available.sort_unstable();
ResponseError::from_msg(
format!("{} fragment `{fragment}` does not exist for embedder `{embedder}`.\n Hint: Available {} fragments are {}.",
format!("{} fragment {} does not exist for embedder {}.\n Hint: Available {} fragments are {}.",
kind.capitalized(),
format_token(&fragment),
format_token(&embedder),
kind.as_str(),
available.iter().map(|s| format!("`{s}`")).collect::<Vec<_>>().join(", ")),
Code::InvalidRenderTemplateId,
)
},
LeftOverToken(token) => ResponseError::from_msg(
format!("Leftover token `{token}` after parsing template ID"),
format!("Leftover token {} after parsing template ID", format_token(&token)),
Code::InvalidRenderTemplateId,
),
MissingChatCompletionTemplate => ResponseError::from_msg(
@ -303,7 +323,7 @@ impl From<RenderError<'_>> for ResponseError {
Code::InvalidRenderTemplateId,
),
UnknownChatCompletionTemplate(id) => ResponseError::from_msg(
format!("Unknown chat completion template ID `{id}`. The only available template is `documentTemplate`."),
format!("Unknown chat completion template ID {}. The only available template is `documentTemplate`.", format_token(&id)),
Code::InvalidRenderTemplateId,
),
DocumentNotFound(doc_id) => ResponseError::from_msg(
@ -331,11 +351,11 @@ impl From<RenderError<'_>> for ResponseError {
Code::InvalidRenderInput,
),
ExpectedDotAfterValue(span) => ResponseError::from_msg(
format!("Expected a dot after value, but found `{span}`."),
format!("Expected a dot after value, but found {}.", format_span(&span)),
Code::InvalidRenderTemplateId,
),
ExpectedValue(span) => ResponseError::from_msg(
format!("Expected a value, but found `{span}`."),
format!("Expected a value, but found {}.", format_span(&span)),
Code::InvalidRenderTemplateId,
),
}
@ -570,7 +590,7 @@ pub struct RenderQueryTemplate {
#[deserr(default, error = DeserrJsonError<InvalidRenderTemplateId>)]
pub id: Option<String>,
#[deserr(default, error = DeserrJsonError<InvalidRenderTemplateInline>)]
pub inline: Option<serde_json::Value>,
pub inline: Option<Value>,
}
#[derive(Debug, Clone, Default, PartialEq, Deserr, ToSchema)]
@ -579,11 +599,11 @@ pub struct RenderQueryInput {
#[deserr(default, error = DeserrJsonError<InvalidRenderInputDocumentId>)]
pub document_id: Option<String>,
#[deserr(default, error = DeserrJsonError<InvalidRenderInputInline>)]
pub inline: Option<BTreeMap<String, serde_json::Value>>,
pub inline: Option<BTreeMap<String, Value>>,
}
#[derive(Debug, Clone, Serialize, PartialEq, ToSchema)]
pub struct RenderResult {
template: serde_json::Value,
rendered: serde_json::Value,
template: Value,
rendered: Value,
}

View File

@ -26,7 +26,7 @@ async fn wrong_id_prefix() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Template ID must start with `embedders` or `chatCompletions`, but found `{wrong}`.",
"message": "Template ID must start with `embedders` or `chatCompletions`, but found `wrong` (cols 1:6).",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -59,7 +59,7 @@ async fn wrong_embedder() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Embedder `{wrong}` does not exist.\n Hint: Available embedders are `rest`.",
"message": "Embedder `wrong` (cols 11:16) does not exist.\n Hint: Available embedders are `rest`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -75,7 +75,7 @@ async fn missing_template_kind() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Template ID configured with `embedders.{rest}` but no template kind provided.\n Hint: Available fragments are `indexingFragments.basic`, `indexingFragments.withBreed`, `searchFragments.justBreed`, `searchFragments.justName`, `searchFragments.query`.",
"message": "Template ID configured with embedder `rest` (cols 11:15) but no template kind provided.\n Hint: Available fragments are `indexingFragments.basic`, `indexingFragments.withBreed`, `searchFragments.justBreed`, `searchFragments.justName`, `searchFragments.query`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -92,7 +92,7 @@ async fn wrong_template_kind() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Wrong template `{wrong}` after embedder `{rest}`.\n Hint: Available fragments are `indexingFragments.basic`, `indexingFragments.withBreed`, `searchFragments.justBreed`, `searchFragments.justName`, `searchFragments.query`.",
"message": "Wrong template `wrong` (cols 16:21) after embedder `rest` (cols 11:15).\n Hint: Available fragments are `indexingFragments.basic`, `indexingFragments.withBreed`, `searchFragments.justBreed`, `searchFragments.justName`, `searchFragments.query`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -109,7 +109,7 @@ async fn document_template_on_fragmented_index() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Requested document template for embedder `{rest}` but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead.",
"message": "Requested document template for embedder `rest` (cols 11:15) but it uses fragments.\n Hint: Use `indexingFragments` or `searchFragments` instead.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -126,7 +126,7 @@ async fn missing_fragment_name() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Indexing fragment name was not provided.\n Hint: Available indexing fragments for embedder `{rest}` are `basic`, `withBreed`.",
"message": "Indexing fragment name was not provided.\n Hint: Available indexing fragments for embedder `rest` (cols 11:15) are `basic`, `withBreed`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -138,7 +138,7 @@ async fn missing_fragment_name() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Search fragment name was not provided.\n Hint: Available search fragments for embedder `{rest}` are `justBreed`, `justName`, `query`.",
"message": "Search fragment name was not provided.\n Hint: Available search fragments for embedder `rest` (cols 11:15) are `justBreed`, `justName`, `query`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -156,7 +156,7 @@ async fn wrong_fragment_name() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Indexing fragment `{wrong}` does not exist for embedder `{rest}`.\n Hint: Available indexing fragments are `basic`, `withBreed`.",
"message": "Indexing fragment `wrong` (cols 34:39) does not exist for embedder `rest` (cols 11:15).\n Hint: Available indexing fragments are `basic`, `withBreed`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -168,7 +168,7 @@ async fn wrong_fragment_name() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Search fragment `{wrong}` does not exist for embedder `{rest}`.\n Hint: Available search fragments are `justBreed`, `justName`, `query`.",
"message": "Search fragment `wrong` (cols 32:37) does not exist for embedder `rest` (cols 11:15).\n Hint: Available search fragments are `justBreed`, `justName`, `query`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -188,7 +188,7 @@ async fn leftover_tokens() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Leftover token `{leftover}` after parsing template ID",
"message": "Leftover token `leftover` (cols 44:52) after parsing template ID",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -201,7 +201,7 @@ async fn leftover_tokens() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Leftover token `{leftover}` after parsing template ID",
"message": "Leftover token `leftover` (cols 42:50) after parsing template ID",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -214,7 +214,7 @@ async fn leftover_tokens() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Leftover token `{leftover}` after parsing template ID",
"message": "Leftover token `leftover` (cols 34:42) after parsing template ID",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -274,7 +274,7 @@ async fn wrong_chat_completions_template() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Unknown chat completion template ID `{wrong}`. The only available template is `documentTemplate`.",
"message": "Unknown chat completion template ID `wrong` (cols 17:22). The only available template is `documentTemplate`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"
@ -638,7 +638,7 @@ async fn embedder_document_template() {
snapshot!(code, @"400 Bad Request");
snapshot!(value, @r#"
{
"message": "Wrong template `{wrong}` after embedder `{rest}`.\n Hint: Available template: `documentTemplate`.",
"message": "Wrong template `wrong` (cols 16:21) after embedder `rest` (cols 11:15).\n Hint: Available template: `documentTemplate`.",
"code": "invalid_render_template_id",
"type": "invalid_request",
"link": "https://docs.meilisearch.com/errors#invalid_render_template_id"