meilisearch / meilisearch/meilisearch-rust

Documentation Error: Rust Tutorial Has Compilation Issues

Open
#770 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

documentation good first issue
Dominant language
Rust
Stars
434
Forks
114
PR merge metrics
No merged PRs in 30d

Description

Hello MeiliSearch team,

First of all, thank you for creating such a wonderful tool!

Summary

I'm following the Getting started with self-hosted Meilisearch tutorial using the Rust SDK. However, I ran into multiple compilation errors when following the tutorial code exactly as written.

Steps to Reproduce

  1. Follow the Rust code examples in the "Add documents" section of the tutorial
  2. Copy the code exactly as shown
  3. Run cargo build and cargo run

The Tutorial Code

The documentation shows this code:
// In your .toml file:
  [dependencies]
  meilisearch-sdk = "0.32.0"
  # futures: because we want to block on futures
  futures = "0.3"
  # serde: required if you are going to use documents
  serde = { version="1.0",   features = ["derive"] }
  # serde_json: required in some parts of this guide
  serde_json = "1.0"



// In your .rs file:
// Documents in the Rust library are strongly typed
#[derive(Serialize, Deserialize)]
struct Movie {
  id: i64,
  title: String,
  poster: String,
  overview: String,
  release_date: i64,
  genres: Vec<String>
}

// You will often need this `Movie` struct in other parts of this documentation. (you will have to change it a bit sometimes)
// You can also use schemaless values, by putting a `serde_json::Value` inside your own struct like this:
#[derive(Serialize, Deserialize)]
struct Movie {
  id: i64,
  #[serde(flatten)]
  value: serde_json::Value,
}

// Then, add documents into the index:
use meilisearch_sdk::{
  indexes::*,
  client::*,
  search::*,
  settings::*
};
use serde::{Serialize, Deserialize};
use std::{io::prelude::*, fs::File};
use futures::executor::block_on;

fn main() { block_on(async move {
  let client = Client::new("http://localhost:7700", Some("aSampleMasterKey"));

  // Reading and parsing the file
  let mut file = File::open("movies.json")
    .unwrap();
  let mut content = String::new();
  file
    .read_to_string(&mut content)
    .unwrap();
  let movies_docs: Vec<Movie> = serde_json::from_str(&content)
    .unwrap();

  // Adding documents
  client
    .index("movies")
    .add_documents(&movies_docs, None)
    .await
    .unwrap();
})}

What I Experienced

When following the tutorial step by step, I encountered three issues. I'd like to share them in case they might be helpful for improving the documentation:

Issue 1: Client::new() Returns a Result and Needs Error Handling

The tutorial code uses:

let client = Client::new("http://localhost:7700", Some("aSampleMasterKey"));

This causes a compilation error:

error[E0599]: no method named `index` found for enum `Result<T, E>` in the current scope
  --> src/main.rs:28:14
   |
27 | / client
28 | |     .index("movies")
   | |      ^^^^^ method not found in `Result<meilisearch_sdk::client::Client, meilisearch_sdk::errors::Error>`
   |
note: the method `index` exists on the type `meilisearch_sdk::client::Client`

Reason: Client::new() returns a Result<Client, Error>, not a Client directly.

Possible fix: One way to address this would be to add error handling:

let client = Client::new("http://localhost:7700", Some("aSampleMasterKey"))
    .unwrap();
Issue 2: Runtime Error - No Tokio Reactor Available

After fixing Issue 1, the code compiles but panics at runtime:

thread 'main' panicked at /Users/.../hyper-util-0.1.20/src/client/legacy/connect/dns.rs:119:24:
there is no reactor running, must be called from the context of a Tokio 1.x runtime
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Reason: The meilisearch-sdk internally uses libraries that require a full Tokio runtime, but futures::executor::block_on doesn't provide one. It only provides a basic executor without the reactor needed for async I/O operations.

Possible fix: Perhaps replacing futures with tokio and using #[tokio::main] might help resolve this issue.

Issue 3: get_task() Cannot Accept Raw u32 Values

The documentation shows checking task status with:

client
  .get_task(0)
  .await
  .unwrap();

However, this code fails to compile with the following error:

error[E0277]: the trait bound `{integer}: AsRef<u32>` is not satisfied
  --> src/main.rs:22:32
   |
22 |     let task = client.get_task(0).await.unwrap();
   |                       --------  ^ the trait `AsRef<u32>` is not implemented for `{integer}`
   |                       |
   |                       required by a bound introduced by this call

Reason: The get_task() method signature requires impl AsRef<u32>, but Rust's standard library doesn't implement AsRef<u32> for the u32 type itself.

Possible approach (might work well): One way could be to use the TaskInfo returned from operations directly, and wait for the task to complete(Otherwise, it might be always showing Processing):

use tokio::time::{sleep, Duration};

// Adding documents returns TaskInfo which implements AsRef<u32>
let task_info = client
    .index("movies")
    .add_documents(&movies_docs, None)
    .await
    .unwrap();

println!("Task enqueued with UID: {}", task_info.get_task_uid());

// Wait for the task to be processed (since tasks are asynchronous)
sleep(Duration::from_secs(2)).await;

// Can pass task_info directly to get_task
let task = client.get_task(task_info).await.unwrap();
println!("Task status: {:#?}", task);

Alternative approach: Another option could be to create a simple wrapper type that implements AsRef<u32> and
we cound retrieve the status of the task in another run:

// Define a wrapper type
struct TaskId(u32);

impl AsRef<u32> for TaskId {
    fn as_ref(&self) -> &u32 {
        &self.0
    }
}

// Use the wrapper
let task = client.get_task(TaskId(0)).await.unwrap();

Possible Solution

One way to address all three issues might be to update both Cargo.toml and the code as follows:

Cargo.toml
[dependencies]
meilisearch-sdk = "0.32.0"
tokio = { version = "1", features = ["full"] }  # Replace futures with tokio
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
src/main.rs
use meilisearch_sdk::client::*;
use serde::{Serialize, Deserialize};
use std::{fs::File, io::prelude::*};
use tokio::time::{Duration, sleep};

#[derive(Serialize, Deserialize, Debug)]
struct Movie {
    id: i64,
    title: String,
    poster: String,
    overview: String,
    release_date: i64,
    genres: Vec<String>,
}

// Optional: wrapper for using raw u32 values with get_task
struct TaskId(u32);

impl AsRef<u32> for TaskId {
    fn as_ref(&self) -> &u32 {
        &self.0
    }
}

#[tokio::main]
async fn main() {
    let client = Client::new("http://localhost:7700", Some("aSampleMasterKey"))
        .unwrap();  // Addresses Issue 1

    // Reading and parsing the file
    let mut file = File::open("movies.json").unwrap();
    let mut content = String::new();
    file.read_to_string(&mut content).unwrap();
    let movies_docs: Vec<Movie> = serde_json::from_str(&content).unwrap();

    println!("Loaded {} movies", movies_docs.len());

    // Adding documents
    let task_info = client
        .index("movies")
        .add_documents(&movies_docs, None)
        .await
        .unwrap();

    println!("Documents added! Task UID: {}", task_info.get_task_uid());

    // Addresses Issue 3: Waiting for task completion, then checking status
    sleep(Duration::from_secs(2)).await;
    let task = client.get_task(task_info).await.unwrap();
    println!("Task status: {:#?}", task);

    // Alternative for Issue 3: Using TaskId wrapper for raw u32
    // let task = client.get_task(TaskId(0)).await.unwrap();
}

Environment

  • Rust version: 1.91.0 (or latest stable)
  • meilisearch 1.35.0
  • meilisearch-sdk: 0.32.0
  • OS: macOS Tahoe 26.2

Additional Notes

I just started learning Rust not long ago and I'm a complete newbie. I'm playing around with Meilisearch to improve my Rust skills by reading your code. If I've misunderstood something or made an error in my analysis, please feel free to correct me or close this issue.

I hope this feedback helps improve the documentation for other newcomers! Thank you for your time and for this amazing project. 🙏

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the Rust tutorial from the linked Getting started page using the shown Cargo.toml and src/main.rs examples with meilisearch-sdk 0.32.0. Start by checking the SDK signatures for Client::new and get_task, then run cargo build and cargo run with the documented runtime. Done means the dependency list and examples compile and execute without the reported runtime or task lookup errors.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.