Skip to content

Always getting 'Broken pipe (os error 32)' but queries do work #3568

@ghost

Description

Bug Description

For all my sqlx queries, I am getting error communicating with database: Broken pipe (os error 32) error and the query gets highlighted in red. However, the code actually works. I can compile it and run it, all queries work without any issues. Somehow it seem like something is wrong and the rust-analyzer marks the code as faulty when there are actually nothing wrong.

Minimal Reproduction

main.rs:

use backend::run;
use log::error;
use log4rs;

#[tokio::main]
async fn main() {
    // Initialize environment variables from .env file
    dotenv::dotenv().ok();

    // Initialize log4rs from the configuration file
    log4rs::init_file("log4rs.yaml", Default::default()).unwrap_or_else(|err| {
        eprintln!("Failed to initialize logger: {:?}", err);
        std::process::exit(1);
    });

    // Run the application and handle any errors
    if let Err(e) = run().await {
        error!("Application error: {:?}", e); 
        eprintln!("Application error: {:?}", e); 
    }
}

lib.rs:

pub mod db;
pub mod handlers;
pub mod middleware;
pub mod models;
pub mod routes;
pub mod services;
pub mod tests;
pub mod validation;

use routes::create_routes;
use std::error::Error;
use std::net::SocketAddr;
use std::sync::Arc;

pub async fn run() -> Result<(), Box<dyn Error>> {
    let db_pool = Arc::new(db::connection::establish_connection().await?);

    let app = create_routes(db_pool.clone());

    let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
    axum::serve(
        listener,
        app.into_make_service_with_connect_info::<SocketAddr>(),
    )
    .await?;

    Ok(())
}

routes/mod.rs:

pub mod legal;


use std::sync::Arc;

use axum::{middleware::from_fn, Router};
use sqlx::MySqlPool;

use crate::middleware::input_validation::input_validation;

pub fn create_routes(pool: Arc<MySqlPool>) -> Router {
    Router::new()
        .nest("/v1/legal", legal::routes(pool.clone()))
        .layer(from_fn(input_validation))
}

routes/legal.rs:

use crate::handlers::legal_handler;
use axum::{routing::get, Router};
use sqlx::mysql::MySqlPool;
use std::sync::Arc;

pub fn routes(pool: Arc<MySqlPool>) -> Router {
    Router::new()
        .route(
            "/terms-and-conditions",
            get(legal_handler::terms_and_conditions),
        )
        .with_state(pool) 
}

handlers/legal_handler.rs:

use crate::models::{
    api_response::ApiResponse,
    legal::{TermsData, TermsQuery},
};
use axum::{
    extract::{Query, State},
    response::IntoResponse,
    Json,
};
use log::error;
use sqlx::mysql::MySqlPool;
use std::sync::Arc; 

pub async fn terms_and_conditions(
    Query(query): Query<TermsQuery>,
    State(pool): State<Arc<MySqlPool>>,
) -> impl IntoResponse {
    match get_latest_terms(&pool, &query.lang_code).await {
        Ok(data) => Json(ApiResponse::success(data)).into_response(),
        Err(sqlx::Error::RowNotFound) => {
            error!("Terms not found for lang_code: {}", query.lang_code);
            (
                axum::http::StatusCode::NOT_FOUND,
                Json(ApiResponse::<()>::error("Terms not found.")),
            )
                .into_response()
        }
        Err(err) => {
            error!("Database query error: {:?}", err);
            (
                axum::http::StatusCode::INTERNAL_SERVER_ERROR,
                Json(ApiResponse::<()>::error("Something went wrong.")),
            )
                .into_response()
        }
    }
}

pub async fn get_latest_terms(pool: &MySqlPool, lang_code: &str) -> Result<TermsData, sqlx::Error> {
    let terms_data = sqlx::query_as!(
        TermsData,
        "
        SELECT date_lang_code, user_agreement, privacy_policy 
        FROM legal 
        WHERE lang_code = ? 
        ORDER BY date_lang_code DESC 
        LIMIT 1
        ",
        lang_code
    )
    .fetch_one(pool)
    .await?;

    Ok(terms_data)
}

The error is happening in the get_latest_terms query. My DB is running in docker on the local machine, I have also tried another DB on a external server but I get the same error. Since I can actually fetch data from the DB, there is nothing wrong with the DB or the connection to it. This issue is only happening in sqlx. We already have other tools using one of these DBs in production since years back and never had any issues, but sqlx returns the same error even when trying the production DB.

This is the docker compose file for the local DB:

services:
  database:
    image: mariadb:latest
    container_name: database
    restart: always
    environment:
      MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
      MYSQL_USER: ${MARIADB_USER}
      MYSQL_PASSWORD: ${MARIADB_PASSWORD}
      MYSQL_DATABASE: db
      MARIADB_AUTO_UPGRADE: "1"
    ports:
      - 3306:3306
    networks: 
      - backend_network
    volumes:
      - ./db_data:/var/lib/mysql

networks:
  backend_network:
    external: true

I don't know if this log could be helpful, but when I run my code as DEBUG, I can see this log in the terminal:

DEBUG - summary="SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION')),time_zone='+00:00',NAMES …" db.statement="\n\nSET\n  sql_mode =(\n    SELECT\n      CONCAT(\n        @ @sql_mode,\n        ',PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION'\n      )\n  ),\n  time_zone = '+00:00',\n  NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;\n" rows_affected=0 rows_returned=0 elapsed=452.381µs elapsed_secs=0.000452381

I also see this warning in the DB logs everytime the rust-analyzer (everytime I click ctrl+s in the project) is running:
Warning] Aborted connection 4 to db: 'db' user: 'user' host: '172.19.0.1' (Got an error reading communication packets)
This is not normal and we are not getting it for anything else.

Info

  • SQLx version: 0.8.2
  • SQLx features enabled: ["runtime-tokio-native-tls", "mysql", "time"]
  • Database server and version: MariaDB 11.5.2. Also tested 11.4.2 and get the same error
  • Operating system: Arch Linux
  • rustc --version: rustc 1.80.1 (3f5fd8dd4 2024-08-06)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions