{"record":{"id":"eacb32f4e59b1924","repo":"linera-io/linera-protocol","slug":"missing-operations-or-messages-from-mandatory-appl","errorCode":null,"errorMessage":"Missing operations or messages from mandatory applications: {0:?}","messagePattern":"Missing operations or messages from mandatory applications: (.+?)","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"error","filePath":"linera-chain/src/chain.rs","lineNumber":1624,"sourceCode":"                        )\n                    );\n                    if let Operation::User { application_id, .. } = operation {\n                        mandatory.remove(application_id);\n                    }\n                }\n                Transaction::ReceiveMessages(incoming_bundle)\n                    if incoming_bundle.action == MessageAction::Accept =>\n                {\n                    for pending in incoming_bundle.messages() {\n                        if let Message::User { application_id, .. } = &pending.message {\n                            mandatory.remove(application_id);\n                        }\n                    }\n                }\n                Transaction::ReceiveMessages(_) => {}\n            }\n        }\n        ensure!(\n            mandatory.is_empty(),\n            ChainError::MissingMandatoryApplications(mandatory.into_iter().collect())\n        );\n        Ok(())\n    }\n\n    /// Validates the chain-state-level preconditions for a `SystemOperation::Checkpoint`:\n    /// no *system* event stream tracker is set.\n    ///\n    /// The structural invariant that `Checkpoint` must be the *first* transaction in its\n    /// block is enforced unconditionally in `execute_block`, independently of these\n    /// preconditions. Sender-side event conditions are validated inside\n    /// `ExecutionStateView::prepare_checkpoint`.\n    async fn check_checkpoint_preconditions(&self) -> Result<(), ChainError> {\n        let mut had_system_event_tracker = false;\n        self.next_expected_events\n            .for_each_index_while(|stream_id| {\n                if matches!(stream_id.application_id, GenericApplicationId::System) {","sourceCodeStart":1606,"sourceCodeEnd":1642,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/chain.rs#L1606-L1642","documentation":"check_app_permissions also enforces mandatory applications: if the chain declares mandatory_applications, every block must contain an operation from — or an accepted message originating from — each mandatory app; covered apps are removed from a running set as transactions are scanned, and any leftover at chain.rs:1624-1627 raises MissingMandatoryApplications. An exempt system operation clears the whole requirement (chain.rs:1596-1600).","triggerScenarios":"Submitting a block that omits a mandatory app's operation/message to a chain configured with mandatory_applications; a block containing only rejected messages when a mandatory app requires accepted activity; unrelated third-party blocks to a chain that mandates specific apps.","commonSituations":"See trigger scenarios.","solutions":["Include at least one operation from each mandatory application in the block (or an accepted incoming message from it)","Include an exempt system operation, which satisfies/clears the mandatory requirement for that block","If the mandate is no longer wanted, change ApplicationPermissions to drop the mandatory app"],"exampleFix":"// before: block missing the mandatory app's transaction\nlet txs = vec![Transaction::ExecuteOperation(other_op)]; // chain mandates app M\n\n// after: ensure every mandatory app is represented\nlet mut txs = vec![Transaction::ExecuteOperation(operation_of_mandatory_app)];\ntxs.push(Transaction::ExecuteOperation(other_op));\nlet block = ProposedBlock { transactions: txs, .. };","handlingStrategy":"validation","validationCode":"// Mirror the mandatory-app coverage check before submitting:\nlet perms = client.chain_info(chain_id).await?.info.application_permissions;\nlet mut mandatory: HashSet<_> = perms.mandatory_applications.iter().copied().collect();\nfor t in &block.transactions {\n    match t {\n        Transaction::ExecuteOperation(op) if op.is_exempt_from_permissions() => { mandatory.clear(); }\n        Transaction::ExecuteOperation(Operation::User { application_id, .. }) => { mandatory.remove(application_id); }\n        Transaction::ReceiveMessages(b) if b.action == MessageAction::Accept => {\n            for m in b.messages() {\n                if let Message::User { application_id, .. } = &m.message { mandatory.remove(application_id); }\n            }\n        }\n        _ => {}\n    }\n}\nanyhow::ensure!(mandatory.is_empty(), \"block missing mandatory apps: {mandatory:?}\");","typeGuard":"fn covers_mandatory_apps(block: &ProposedBlock, perms: &ApplicationPermissions) -> bool {\n    let mut mandatory: HashSet<_> = perms.mandatory_applications.iter().copied().collect();\n    for t in &block.transactions {\n        match t {\n            Transaction::ExecuteOperation(op) if op.is_exempt_from_permissions() => mandatory.clear(),\n            Transaction::ExecuteOperation(Operation::User { application_id, .. }) => { mandatory.remove(application_id); }\n            Transaction::ReceiveMessages(b) if b.action == MessageAction::Accept => {\n                for m in b.messages() {\n                    if let Message::User { application_id, .. } = &m.message { mandatory.remove(application_id); }\n                }\n            }\n            _ => {}\n        }\n    }\n    mandatory.is_empty()\n}","tryCatchPattern":"match result {\n    Err(ChainError::MissingMandatoryApplications(missing)) => {\n        // add an operation or accepted message for each app in `missing`, or include\n        // an exempt system operation which satisfies the mandate\n    }\n    other => other?,\n}","preventionTips":["Read mandatory_applications from chain state when building blocks for restricted chains","Remember an exempt system operation satisfies the mandate for the block","Keep permission config with the app deployment docs so block builders know the rules"],"tags":["linera","application-permissions","mandatory-apps","block","rust"],"backgroundTag":"mandatory-app-missing","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}