Vince Yau
Vince Yau

Reputation: 555

Unable to update Google Drive files using Drive API v3 -- The resource body includes fields which are not directly writable

I am trying to use Google Drive API (v3) to make updates to documents in Google Drive.

I have read this migration guide: Google Drive API v3 Migration

And coded it to make a new empty File() with the details I want to update and then calling execute() with that and the file ID. But i am still getting an error. Can anyone point out where I am doing wrong? thanks alot!!

Error:

{
    "code" : 403,
    "errors" : [{
        "domain" : "global",

        "message" : "The resource body includes fields which are not directly writable.",

        "reason" : "fieldNotWritable"
    }],
    "message" : "The resource body includes fields which are not directly writable."
}

Code snippet below:

File newFileDetails = new File();        
FileList result = service2.files().list()
    .setPageSize(10)    
    .setFields("nextPageToken, files(id, name)")
    .execute();

List<File> files = result.getFiles();

if (files == null || files.size() == 0) {

    System.out.println("No files found.");

} else {

   System.out.println("Files:");

   for (File file : files) {

      if (file.getName().equals("first_sheet")) {

         System.out.printf("%s (%s)\n", file.getName(), file.getId());


         newFileDetails.setShared(true);


         service2.files().update(file.getId(), newFileDetails).execute();

      }

   }

}

Upvotes: 11

Views: 13633

Answers (6)

DavGarcia
DavGarcia

Reputation: 18812

I was getting a similar error. This was from first getting a file and then trying to run update on that file. The Id of the file is not writable, so has to be set to null before calling the Update, like this:

        var getRequest = driveService.Files.Get(Id);
        var file = await getRequest.ExecuteAsync();
        var id = file.Id;
        file.Id = null; // Must clear Id as that property is not writable.

        var updateRequest = driveService.Files.Update(file, id);
        // Move the file to a folder
        updateRequest.SupportsAllDrives = true;
        updateRequest.AddParents = parentFolderId;
        var movedFile = await updateRequest.ExecuteAsync();

The ID of the file is not changed by the update request.

Upvotes: 0

Kishan Gurumurthy
Kishan Gurumurthy

Reputation: 1

I strongly think the error is directly connected to the permissions. Please check this format!

import com.google.api.services.drive.model.Permission;

FileList result = service2.files().list()
    .setPageSize(10)
    .setFields("nextPageToken, files(id, name)")
    .execute();

List<File> files = result.getFiles();

if (files == null || files.isEmpty()) {
    System.out.println("No files found.");
} else {
  System.out.println("Files:");

for (File file : files) {
    if (file.getName().equals("first_sheet")) {
        System.out.printf("%s (%s)\n", file.getName(), file.getId());

        Permission permission = new Permission();
        permission.setRole("reader"); 
        permission.setType("anyone");

        service2.permissions().create(file.getId(), permission).execute();
    }
  }
}

Upvotes: 0

Serge-M
Serge-M

Reputation: 29

I was doing the same thing. My goal was to share my file programmatically with my Python code.

And yes, I was getting the same error: "The resource body includes fields which are not directly writable"

I solved this problem by adding the service's email address of my Virtual Machine (I created it on my Compute Engine dashboard) to Editors of the file.

Then I ran this Python code in my VM:

from googleapiclient.discovery import build
from oauth2client.service_account import ServiceAccountCredentials


# Took the json file from my Google Cloud Platform (GCP) → IAM & Admin → Service Accounts:
service_key_file = 'service_key.json'
scope = 'https://www.googleapis.com/auth/drive'

credentials = ServiceAccountCredentials.from_json_keyfile_name(service_key_file, scopes=scope)
driveV3 = build('drive', 'v3', credentials=credentials)

fileId = '1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ'  # A spreadsheet file on my GDrive.

newGmailUser = '[email protected]'
permNewBody = {
    'role': 'reader',
    'type': 'user',
    'emailAddress': newGmailUser,
}


driveV3.permissions().create(fileId=fileId, body=permNewBody).execute()
print(f"""The file is now shared with this user:
{newGmailUser}\n
See the file here:
https://docs.google.com/spreadsheets/d/1ZP1xZ0WaH8w2yaQTSx99gafNZWawQabcdVW5DSngavQ""")

Upvotes: 0

Alex Shevelev
Alex Shevelev

Reputation: 691

I had the same issue and found a solution. The key point is: you must create a new File object without Id and use it in update() method. Here is a piece of my code:

val oldMetadata = service!!.files().get(fileId.id).execute()

val newMetadata = File()
newMetadata.name = oldMetadata.name
newMetadata.parents = oldMetadata.parents
newMetadata.description = idHashPair.toDriveString()

val content = ByteArrayContent("application/octet-stream", fileContent)

val result = service!!.files().update(fileId.id, newMetadata, content).execute()

It works. I hope it'll help you.

Upvotes: 6

Mark Fieldman
Mark Fieldman

Reputation: 94

in the code it looks like this

Drive service... // your own declared implementation of service
File  file = new File(); //using the com.google.api.services.drive.model package
    // part where you set your data to file like:
file.setName("new name for file");
String fileID = "id of file, which you want to change";
service.files().update(fileID,file).execute();

trying to change the fields from remote files, and rewriting to this file can throw the security exception like exception below. but it is not a solution for your question. If you want to share file to another google account by email, you can do it with reimplementing authorization to authorization with using service account of your app, and the add the needed email, as owner of the file.

Upvotes: 3

pinoyyid
pinoyyid

Reputation: 22306

Referring to https://developers.google.com/drive/v3/reference/files#resource-representations, you can see that shared isn't a writable field. If you think about it, this makes perfect sense. You can share a file by adding a new permission, and you can check if a file has been shared by reading the shared property. But saying a file is shared, other than by actually sharing it, makes no sense.

Upvotes: 3

Related Questions