{"record":{"id":"98a4b678bb544e34","repo":"linera-io/linera-protocol","slug":"a-running-notification-server","errorCode":null,"errorMessage":"a running notification server","messagePattern":"a running notification server","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-exporter/src/exporter_service.rs","lineNumber":96,"sourceCode":"        cancellation_token: CancellationToken,\n    ) -> core::result::Result<(), ExporterError> {\n        let endpoint = get_address(port);\n        info!(\n            \"Starting linera_exporter_service on endpoint = {}\",\n            endpoint\n        );\n\n        let (health_reporter, health_service) = tonic_health::server::health_reporter();\n        health_reporter\n            .set_serving::<NotifierServiceServer<Self>>()\n            .await;\n\n        Server::builder()\n            .add_service(health_service)\n            .add_service(NotifierServiceServer::new(self))\n            .serve_with_shutdown(endpoint, cancellation_token.cancelled_owned())\n            .await\n            .expect(\"a running notification server\");\n\n        Ok(())\n    }\n}\n\nfn parse_notification(notification: Notification) -> core::result::Result<BlockId, ExporterError> {\n    let chain_id = notification\n        .chain_id\n        .ok_or(BadNotificationKind::InvalidChainId { inner: None })?\n        .try_into()\n        .map_err(|err| BadNotificationKind::InvalidChainId { inner: Some(err) })?;\n\n    let reason = bincode::deserialize::<Reason>(&notification.reason)\n        .map_err(|err| BadNotificationKind::InvalidReason { inner: Some(err) })?;\n\n    if let Reason::NewBlock { height, hash } = reason {\n        return Ok(BlockId::new(chain_id, hash, height));\n    }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-exporter/src/exporter_service.rs#L78-L114","documentation":"start_notification_server (linera-exporter/src/exporter_service.rs) serves the gRPC NotifierServiceServer on the configured endpoint with serve_with_shutdown and expects success. The expect fires when tonic fails to serve the endpoint - overwhelmingly a bind failure such as 'address already in use', plus invalid endpoint addresses or socket permission errors. This runs during exporter startup, so the process aborts before serving notifications.","triggerScenarios":"Starting linera-exporter when the notification server port (from the config's notification section) is already bound by another process - a second exporter instance, a validator proxy using the same port, or a leftover process. Also a malformed endpoint address in the config.","commonSituations":"Duplicate exporter instances in a container/k8s setup pointing at the same port; port collision between the exporter's notification server and another service; stale process still holding the port after a crash.","solutions":["Find and stop the process holding the port: `ss -ltnp | grep <port>` or `lsof -i :<port>`, then kill it.","Change the notification port in the exporter config to a free one.","Verify the endpoint address format in the config (e.g. 0.0.0.0:PORT or 127.0.0.1:PORT).","If two exporters are intended, give each its own notification port."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before starting the exporter, verify the notification port is free:\nlet probe = tokio::net::TcpListener::bind(notification_endpoint).await;\nmatch probe {\n    Ok(l) => drop(l), // port free; brief TOCTOU window is acceptable at startup\n    Err(e) if e.kind() == std::io::ErrorKind::AddrInUse => {\n        return Err(anyhow::anyhow!(\"notification port already in use: {notification_endpoint}\"));\n    }\n    Err(e) => return Err(e.into()),\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assign each exporter instance a distinct notification port in its config.","In containers, let the orchestrator allocate host ports instead of hardcoding.","After startup, health-check the gRPC endpoint (e.g. grpcurl health check) to confirm it bound."],"tags":["linera-exporter","grpc","port-in-use","notification-server","panic"],"backgroundTag":"address-already-in-use","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}