Search code examples
google-apps-scriptgoogle-drive-apifile-permissionshttp-status-code-400

How to copy/set file and folder permission ("The emailAddress field is required" error)


I have written a script that copies Google Drive files and folders. I would like the permissions to be copied as well, but for some strange reason, this doesn’t fully work. Even ChatGPT couldn’t find the mistake, and online resources did not help me either.

What am I doing wrong here?

I manage to copy permissions related to "anyoneWithLink," but specific user permissions do not copy. Why is this happening?

Here is the function I’m using to copy the permissions:

function copyPermissionsUsingDriveAPI(sourceId, targetId) {
    try {
        // Fetch permissions from the source file/folder
        const permissionsResponse = Drive.Permissions.list(sourceId, { supportsAllDrives: true });

        // Extract permissions
        const permissions = permissionsResponse.permissions || permissionsResponse.items || [];
        if (!permissions || permissions.length === 0) return;

        // Filter out owner permissions
        const nonOwnerPermissions = permissions.filter(permission => permission.role !== 'owner');
        if (nonOwnerPermissions.length === 0) return;

        nonOwnerPermissions.forEach(permission => {
            try {
                // Prepare the permission payload
                const newPermission = {
                    role: permission.role,
                    type: permission.type
                };

                if (permission.type === 'anyone') {
                    newPermission.allowFileDiscovery = permission.allowFileDiscovery || false;
                } else if (permission.type === 'user' || permission.type === 'group') {
                    newPermission.emailAddress = permission.emailAddress || null;
                }

                // Make a direct API request to copy the permission
                const url = `https://www.googleapis.com/drive/v3/files/${targetId}/permissions`;
                const options = {
                    method: 'post',
                    contentType: 'application/json',
                    headers: {
                        Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
                    },
                    payload: JSON.stringify(newPermission)
                };

                UrlFetchApp.fetch(url, options);
            } catch (error) {
               Logger.log(`Error setting permissions: ${error.message}`);
                // Gracefully skip problematic permissions
            }
        });
    } catch (error) {
       Logger.log(`Error fetching permissions: ${error.message}`);
        // Gracefully handle permission fetching errors
    }
}

The error message I get is:

Error setting permissions: Request failed for https://www.googleapis.com returned code 400. Truncated server response: {
  "error": {
    "code": 400,
    "message": "The emailAddress field is required for permissions of type 'user' or 'group'.",
    "errors": [
   .. (use muteHttpExceptions option to examine full response).

How do I get the email address?
When I tried to read it the field was empty.
Why is it necessary? Shouldn’t there be a way to do this using only the user ID?

I have seen another script in action that achieves this. So, how did that one work?


Solution

  • From your current issue and permissionsResponse.permissions, I guessed that your situation might be the same with this thread. So, how about the following modification?

    From:

    const permissionsResponse = Drive.Permissions.list(sourceId, { supportsAllDrives: true });
    

    To:

    const permissionsResponse = Drive.Permissions.list(sourceId, { supportsAllDrives: true, fields: "*" });
    
    • When I tested your script const permissionsResponse = Drive.Permissions.list(sourceId, { supportsAllDrives: true }), the value of emailAddress is not included in the response value. When fields: "*" is used, it could be included.

    Reference: