{"record":{"id":"862c86efb6a85b2f","repo":"block/buzz","slug":"invalid-media-config-e","errorCode":null,"errorMessage":"invalid media config: {e}","messagePattern":"invalid media config: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/buzz-relay/src/main.rs","lineNumber":512,"sourceCode":"        .unwrap_or(&config.database_url);\n    let search_pool = sqlx::postgres::PgPoolOptions::new()\n        .connect(search_db_url)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Search DB connection failed: {e}\"))?;\n    let search_metrics_pool = search_pool.clone();\n    let search = SearchService::new(search_pool);\n    info!(\n        replica = config.read_database_url.is_some(),\n        \"Search service ready (Postgres FTS)\"\n    );\n\n    let workflow_config = buzz_workflow::WorkflowConfig::default();\n    let workflow_engine = Arc::new(WorkflowEngine::new(db.clone(), workflow_config));\n\n    config\n        .media\n        .validate()\n        .map_err(|e| anyhow::anyhow!(\"invalid media config: {e}\"))?;\n    let media_storage = buzz_media::MediaStorage::new(&config.media)\n        .map_err(|e| anyhow::anyhow!(\"failed to initialize media storage: {e}\"))?;\n    info!(\"Media storage connected\");\n\n    let (app_state, audit_shutdown) = AppState::new(\n        config.clone(),\n        db,\n        redis_health_pool,\n        audit,\n        pubsub,\n        auth,\n        search,\n        Arc::clone(&workflow_engine),\n        relay_keypair,\n        media_storage,\n    );\n    let state = Arc::new(app_state);\n","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/block/buzz/blob/ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be/crates/buzz-relay/src/main.rs#L494-L530","documentation":"Fatal startup error: MediaConfig::validate() rejected the media/S3 configuration before MediaStorage construction. The checks are concrete: public_base_url must end with /media and must not end with /; max_image_bytes > 0; max_gif_bytes in (0, max_image_bytes]; max_video_bytes and max_file_bytes > 0; an upload IP header without upload records enabled is rejected; a port header without an IP header is rejected.","triggerScenarios":"BUZZ_MEDIA_PUBLIC_BASE_URL missing the /media suffix or carrying a trailing slash; a size limit var set to 0; max GIF size larger than max image size; BUZZ_MEDIA_UPLOAD_IP_HEADER set while BUZZ_MEDIA_UPLOAD_RECORDS is not enabled; BUZZ_MEDIA_UPLOAD_PORT_HEADER set without the IP header.","commonSituations":"Pointing public_base_url at a CDN root instead of the /media path; tuning size limits to \"unlimited\" by entering 0 (which actually means invalid); enabling IP reporting without turning on the records that store it.","solutions":["Set BUZZ_MEDIA_PUBLIC_BASE_URL to a URL ending exactly with /media and no trailing slash (e.g. https://cdn.example.com/media)","Make all size limits positive integers, with max_gif_bytes <= max_image_bytes","Either enable BUZZ_MEDIA_UPLOAD_RECORDS=true when an upload IP header is configured, or unset the header","Unset the port header unless the IP header is also set"],"exampleFix":"# before\nexport BUZZ_MEDIA_PUBLIC_BASE_URL=https://cdn.example.com\nexport BUZZ_MAX_IMAGE_BYTES=0\n\n# after\nexport BUZZ_MEDIA_PUBLIC_BASE_URL=https://cdn.example.com/media\nexport BUZZ_MAX_IMAGE_BYTES=52428800","handlingStrategy":"validation","validationCode":"# Deploy-time guard:\n: \"${BUZZ_MEDIA_PUBLIC_BASE_URL:?}\"\ncase \"$BUZZ_MEDIA_PUBLIC_BASE_URL\" in\n  */media) ;;               # ok, no trailing slash beyond /media\n  *) echo 'BUZZ_MEDIA_PUBLIC_BASE_URL must end with /media'; exit 1 ;;\nesac","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep public_base_url ending exactly with /media and never with a trailing slash","Use positive sizes for all upload limits and keep gif <= image limit","Enable BUZZ_MEDIA_UPLOAD_RECORDS whenever an upload IP header is configured"],"tags":["config","media","s3","validation","startup","buzz-relay"],"backgroundTag":"invalid-configuration","analyzedSha":"ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":"2026-08-20T04:38:24.874Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}