{"record":{"id":"ae6cc99494066838","repo":"Pumpkin-MC/Pumpkin","slug":"marketplace-http-error-0","errorCode":null,"errorMessage":"Marketplace HTTP error: {0}","messagePattern":"Marketplace HTTP error: (.+?)","errorType":"exception","errorClass":"LicenseError","httpStatus":null,"severity":"error","filePath":"crates/pumpkin-plugin-utils/src/license.rs","lineNumber":18,"sourceCode":"//! License validation, leasing, and offline grace periods.\n\nuse crate::{\n    http::{HttpClient, HttpError},\n    models::{CheckLicenseResponse, LicenseLease, LicenseStatus, PumpkinMetadata},\n};\nuse std::{\n    path::{Path, PathBuf},\n    time::{Duration, SystemTime, UNIX_EPOCH},\n};\nuse thiserror::Error;\nuse tracing::{debug, info};\n\n/// License checking and verification errors.\n#[derive(Debug, Error)]\npub enum LicenseError {\n    /// HTTP communication error with marketplace.\n    #[error(\"Marketplace HTTP error: {0}\")]\n    Http(#[from] HttpError),\n    /// Metadata validation error (e.g. missing license on paid plugin).\n    #[error(\"License metadata mismatch: {0}\")]\n    MetadataMismatch(String),\n    /// License revoked or refunded by marketplace.\n    #[error(\"License was revoked or refunded: {0}\")]\n    Revoked(String),\n    /// License is expired.\n    #[error(\"License has expired on {0}\")]\n    Expired(String),\n    /// I/O error reading/writing license cache.\n    #[error(\"I/O error with license storage: {0}\")]\n    Io(#[from] std::io::Error),\n    /// JSON serialization error.\n    #[error(\"JSON serialization error: {0}\")]\n    Json(#[from] serde_json::Error),\n    /// Plugin is unsigned or missing marketplace metadata.\n    #[error(\"Plugin is unsigned or missing marketplace metadata\")]","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-plugin-utils/src/license.rs#L1-L36","documentation":"LicenseError::Http wraps any HttpError (#[from]) raised while communicating with the marketplace's license/verification REST API. It means the license check could not complete due to an HTTP-level failure (request failed, non-2xx status, or unreadable body), not a licensing decision.","triggerScenarios":"Calling license verification functions (e.g. LicenseManager check/verify paths) when the marketplace endpoint is unreachable, returns an error status (HttpError::BadStatus), or its response body cannot be read (HttpError::BodyRead); the HttpError is auto-converted via #[from].","commonSituations":"Marketplace API downtime or maintenance; wrong marketplace URL/base configuration; invalid or missing API credentials causing 401/403; DNS or firewall blocking the endpoint; offline server attempting an online license check.","solutions":["Read the inner HttpError ({0}) to distinguish request-failure vs bad status vs body-read.","Verify marketplace base URL and credentials in plugin configuration.","Confirm network reachability to the marketplace endpoint (curl/ping).","Check marketplace service status; retry with backoff if transient.","Implement offline/grace behavior around the license check using the library's cached lease instead of failing hard."],"exampleFix":"// before\nlet license = manager.verify()?; // Http bubbles up\n// after\nlet license = match manager.verify() {\n    Ok(l) => l,\n    Err(LicenseError::Http(e)) => { tracing::error!(\"marketplace unreachable: {e}\"); manager.cached_lease().ok_or(e)? }\n    Err(e) => return Err(e),\n};","handlingStrategy":"fallback","validationCode":"// Pre-flight reachability + config sanity before license verification\nassert!(!marketplace_base_url.is_empty(), \"marketplace URL configured\");\nlet reachable = reqwest::blocking::get(format!(\"{base}/health\")).is_ok();\nif !reachable { return offline_mode(); }","typeGuard":"fn is_http_failure(e: &LicenseError) -> bool {\n    matches!(e, LicenseError::Http(_))\n}","tryCatchPattern":"match manager.verify() {\n    Ok(license) => activate(license),\n    Err(LicenseError::Http(e)) => {\n        tracing::warn!(\"marketplace HTTP failure: {e}; using cached lease\");\n        manager.cached_lease().unwrap_or_else(fallback_unlicensed)\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Configure the correct marketplace base URL and credentials up front.","Implement an offline grace mode backed by the cached license lease.","Alert on repeated Http errors to catch marketplace outages early.","Keep plugin-utils updated for marketplace API compatibility."],"tags":["http","license","network","rust"],"backgroundTag":"upstream-api-error","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}