duplicati/duplicati · error · UserInformationException
GoogleCloudStorageMissingFullControlScope
GoogleCloudStorageMissingFullControlScope
Error message
The supplied credentials are missing the full control scope. Please use a service account with full control access.
What it means
In SetObjectLockUntilAsync, before issuing the PATCH that sets retention, Duplicati builds an OAuth client with the 'full control' scope; if m_create_oauth_fullcontrol() returns null (the configured credentials do not grant devstorage.full_control), it throws UserInformationException code 'GoogleCloudStorageMissingFullControlScope'. Setting object retention metadata requires write access to the bucket/object ACLs and retention, which read-only scopes cannot provide.
Source
Thrown at Duplicati/Library/Backend/GoogleServices/GoogleCloudStorage.cs:285
{
var url = WebApi.GoogleCloudStorage.MetadataUrl(m_bucket, Utility.UrlEncoding.UrlPathEncode(m_prefix + remotename));
var metadata = new ObjectMetadata
{
retention = new Retention
{
mode = m_retention_policy_mode.ToString(),
retainUntilTime = lockUntilUtc
}
};
try
{
if (m_oauth_fullcontrol == null)
m_oauth_fullcontrol = m_create_oauth_fullcontrol();
if (m_oauth_fullcontrol == null)
throw new UserInformationException(Strings.GoogleCloudStorage.MissingFullControlScopeError, "GoogleCloudStorageMissingFullControlScope");
using var req = await m_oauth_fullcontrol.CreateRequestAsync(url, new HttpMethod("PATCH"), cancellationToken).ConfigureAwait(false);
req.Content = JsonContent.Create(metadata);
req.Headers.Add("Accept", "application/json");
using var resp = await m_oauth_fullcontrol.GetResponseAsync(req, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
}
catch (HttpRequestException hrex)
{
if (hrex.StatusCode == HttpStatusCode.NotFound)
throw new FileMissingException();
throw;
}
}
public Task TestAsync(bool alsoWrite, CancellationToken cancelToken)
=> this.TestBackendAsync(alsoWrite, cancelToken);
View on GitHub (pinned to 3f348be3e3)
Solutions
- Re-authorize the OAuth flow (or the service account) with the devstorage.full_control scope and re-supply credentials.
- If using a service-account JSON, confirm its project/role grants roles/storage.objectAdmin (or equivalent) and the scope includes full_control.
- Disable --gcs-retention-policy-mode if you do not actually need retention, allowing the lower-scope credentials to work.
- Clear any cached OAuth token from the lower-scope authorization before retrying.
Example fix
// before
if (m_oauth_fullcontrol == null)
throw new UserInformationException(Strings.GoogleCloudStorage.MissingFullControlScopeError, "GoogleCloudStorageMissingFullControlScope");
// after (name the missing scope so the user knows exactly what to re-grant)
if (m_oauth_fullcontrol == null)
throw new UserInformationException(
"The supplied credentials are missing the devstorage.full_control scope, which is required to set object retention. Re-authorize with full control access.",
"GoogleCloudStorageMissingFullControlScope"); Defensive patterns
Strategy: validation
Validate before calling
// Verify the full-control scope is granted before attempting to set retention
if (!HasScope(credentials, "https://www.googleapis.com/auth/devstorage.full_control"))
throw new InvalidOperationException("Re-authorize with devstorage.full_control to use object retention."); Try / catch
try { await backend.SetObjectLockUntilAsync(remotename, until, ct); }
catch (UserInformationException ex) when (ex.HelpID == "GoogleCloudStorageMissingFullControlScope")
{
Console.Error.WriteLine("Re-authorize GCS credentials with the full_control scope to set retention.");
throw;
} Prevention
- Authorize OAuth with devstorage.full_control from the start if you plan to use retention.
- For service accounts, grant roles/storage.objectAdmin and include the full_control scope.
- Do not enable --gcs-retention-policy-mode with read-only/read-write credentials.
- Clear cached lower-scope tokens before retrying with the wider scope.
When it happens
Trigger: The user configured GCS with credentials whose OAuth scope lacks https://www.googleapis.com/auth/devstorage.full_control (e.g. only read_only or read_write), then attempted to set an object-lock / retention policy. m_create_oauth_fullcontrol() returns null because the requested scope is unavailable for those credentials.
Common situations: Using a service-account JSON or OAuth flow scoped to read_only/read_write and then enabling --gcs-retention-policy-mode; authorizing via an OAuth consent screen that only requests read scope; reusing a token cached from a lower-scope authorization.
Related errors
- FileMissing
- GoogleCloudStorageMissingProjectID
- FailedToCreateDataFolder
- InsecureDataFolderPermissions
- InsecurePreloadFilePermissions
AI-assisted analysis of duplicati/duplicati@3f348be3e3 (2026-08-13).
Data as JSON: /api/errors/0cb71f3100ab400f.
Report an issue: GitHub.