linera-io/linera-protocol · error · ExecutionError
UnauthorizedApplication
UnauthorizedApplication
Error message
ExecutionError::UnauthorizedApplication(app_id)
What it means
Linera's execution runtime rejects an application's outbound HTTP request when the chain's ApplicationPermissions do not allow it. The chain stores an optional make_http_requests list: None means every application may make HTTP requests, Some(list) means only the listed application IDs. This check runs in the shared BaseRuntime::perform_http_request (runtime.rs:947), so it applies to both contract and service HTTP oracle calls, and failing it aborts the whole block, not just the call.
Source
Thrown at linera-execution/src/runtime.rs:947
read_size += key.len() + value.len();
}
this.resource_controller
.track_bytes_read(read_size as u64)?;
Ok(key_values)
}
fn perform_http_request(
&mut self,
request: http::Request,
) -> Result<http::Response, ExecutionError> {
let mut this = self.inner();
let app_permissions = this
.execution_state_sender
.send_request(|callback| ExecutionRequest::GetApplicationPermissions { callback })?
.recv_response()?;
let app_id = this.current_application().id;
ensure!(
app_permissions.can_make_http_requests(&app_id),
ExecutionError::UnauthorizedApplication(app_id)
);
this.resource_controller.track_http_request()?;
this.execution_state_sender
.send_request(|callback| ExecutionRequest::PerformHttpRequest {
request,
http_responses_are_oracle_responses:
Self::LIMIT_HTTP_RESPONSE_SIZE_TO_ORACLE_RESPONSE_SIZE,
callback,
})?
.recv_response()
}
fn assert_before(&mut self, timestamp: Timestamp) -> Result<(), ExecutionError> {
let this = self.inner();View on GitHub (pinned to 6c226ddcb3)
Solutions
- Submit SystemOperation::ChangeApplicationPermissions from the chain owner, adding this application's ID to make_http_requests (or setting it to None to allow all apps on that chain).
- If the chain was opened with restrictive permissions, open or re-create the chain with ApplicationPermissions that include the app in make_http_requests.
- If you do not own the chain, ask its owner to update the permissions; the error cannot be bypassed from the application side.
- If permissions cannot be changed, remove the HTTP call from the application and feed the data in via operations or blobs instead.
Example fix
// before
let response = runtime.perform_http_request(request)?; // fails: UnauthorizedApplication
// after (one-time setup by the chain owner, then the call succeeds)
// chain.submit(SystemOperation::ChangeApplicationPermissions(
// ApplicationPermissions { make_http_requests: Some(vec![app_id]), ..Default::default() }))
let response = runtime.perform_http_request(request)?; Defensive patterns
Strategy: validation
Validate before calling
// Before running the app's block, check the chain's permissions (e.g. via the node client / GraphQL):
// let perms = node.chain_info(chain_id).await?.application_permissions;
let allowed = perms.make_http_requests
.as_ref()
.map_or(true, |ids| ids.contains(&app_id));
if !allowed {
// submit ChangeApplicationPermissions first, or abort with a clear config error
} Try / catch
match result {
Err(ExecutionError::UnauthorizedApplication(app_id)) => {
// deterministic until permissions change: do NOT retry;
// report that app_id needs make_http_requests on this chain
}
other => other,
} Prevention
- Keep ApplicationPermissions in config-as-code next to the app deployment and review them in CI.
- Whenever bytecode republish changes the ApplicationId, re-grant make_http_requests for the new ID.
- Test HTTP-calling apps on a chain whose permissions mirror production before deploying.
When it happens
Trigger: Calling ContractRuntime::perform_http_request or the service runtime's HTTP API from an application whose ID is not in the chain's make_http_requests list. Typically after a SystemOperation::ChangeApplicationPermissions set an explicit list that omits the app, or after OpenChain created the chain with restrictive permissions (e.g. ApplicationPermissions configured for a different app).
Common situations: Deploying an HTTP-calling app on a chain created for another application; updating permissions to Some(vec![...]) and forgetting the new app; re-publishing bytecode so the app gets a new ApplicationId without re-granting permission; copying a genesis or chain config with a restrictive permission list into a test setup.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- ClosedChain
- CannotRejectMessage
- All operations on this chain must be from one of the followi
- Missing operations or messages from mandatory applications:
- BlockHeightOverflow
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/6aa53fd0e38d7acf.
Report an issue: GitHub.