{"record":{"id":"9bcf9fe573677534","repo":"databendlabs/databend","slug":"stage-prefix-should-never-be-called-on-external-st","errorCode":null,"errorMessage":"stage_prefix should never be called on external stage, must be a bug","messagePattern":"stage_prefix should never be called on external stage, must be a bug","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/app/src/principal/user_stage.rs","lineNumber":516,"sourceCode":"    }\n\n    pub fn with_allow_credential_chain(mut self, allow: bool) -> StageInfo {\n        self.allow_credential_chain = allow;\n        self\n    }\n\n    /// Get the prefix of stage.\n    ///\n    /// Use this function to get the prefix of this stage in the data operator.\n    ///\n    /// # Notes\n    ///\n    /// This function should never be called on external stage because it's meanless. Something must be wrong.\n    pub fn stage_prefix(&self) -> String {\n        match self.stage_type {\n            StageType::LegacyInternal => format!(\"/stage/{}/\", self.stage_name),\n            StageType::External => {\n                unreachable!(\"stage_prefix should never be called on external stage, must be a bug\")\n            }\n            StageType::Internal => format!(\"/stage/internal/{}/\", self.stage_name),\n            StageType::User => format!(\"/stage/user/{}/\", self.stage_name),\n        }\n    }\n}\n\n#[derive(Default, Debug, Clone, PartialEq, Eq)]\npub struct StageFile {\n    pub path: String,\n    pub size: u64,\n    pub md5: Option<String>,\n    pub last_modified: DateTime<Utc>,\n    pub creator: Option<UserIdentity>,\n    pub etag: Option<String>,\n}\n","sourceCodeStart":498,"sourceCodeEnd":533,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/meta/app/src/principal/user_stage.rs#L498-L533","documentation":"UserStage::stage_prefix builds a filesystem-style prefix (/stage/...) for internal/user stages. For StageType::External it deliberately panics with unreachable!(), because an external stage's location lives outside the service and has no such prefix; calling it there is documented as a bug. The caller init_stage_operator is expected to route external stages to a different code path.","triggerScenarios":"Calling stage_prefix() on a stage whose stage_type is StageType::External — e.g. init_stage_operator (or new code) failing to check stage_type before computing a prefix for an external/object-storage stage.","commonSituations":"Creating an operator for a user-created external stage pointing at object storage; refactors that unified internal and external stage handling but forgot the external branch; stages persisted with the wrong stage_type.","solutions":["In the caller, branch on stage_type and use the external storage location directly for StageType::External, never stage_prefix().","Guard with a stage_type check before calling stage_prefix().","If the stage should be internal, fix how the stage was created (CREATE STAGE vs external location) so stage_type is correct."],"exampleFix":"// before\nlet prefix = stage.stage_prefix();\n// after\nif stage.stage_type == StageType::External {\n    let prefix = stage.external_location_prefix();\n} else {\n    let prefix = stage.stage_prefix();\n}","handlingStrategy":"validation","validationCode":"if stage.stage_type == StageType::External {\n    // use external location instead of stage_prefix()\n}","typeGuard":null,"tryCatchPattern":"match stage.stage_type {\n    StageType::External => init_external_operator(stage)?,\n    _ => init_internal_operator_with_prefix(stage, stage.stage_prefix()),\n}","preventionTips":["Always branch on StageType before building a stage prefix or operator.","Remember external stages have no /stage/ prefix; use their storage location.","Verify stage_type is persisted correctly at CREATE STAGE time.","Add tests that run operator init for every StageType variant."],"tags":["rust","panic","stage","external-storage","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}