Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ApolloError: Internal server error] #15

Open
DevelopMod opened this issue Nov 15, 2023 · 11 comments
Open

[ApolloError: Internal server error] #15

DevelopMod opened this issue Nov 15, 2023 · 11 comments

Comments

@DevelopMod
Copy link

I have made it like this, this is not an error but I also do not understand, if the issue is my setup or the problem with wp-graphql-upload.

Can you please review it?
thanks

		register_graphql_mutation('uploadProfilePicture', [
			'inputFields' => [
				'file' => [
					'type' => 'Upload',
				],
			],
			'outputFields' => [
				'avatarUrl' => [
					'type' => 'String',
					'resolve' => function ($payload) {
						return $payload['avatarUrl'];
					}
				],
				'avatarUrlThumbnail' => [
					'type' => 'String',
					'resolve' => function ($payload) {
						return $payload['avatarUrlThumbnail'];
					}
				],
				'successMessage' => [
					'type' => 'Boolean',
					'resolve' => function ($payload) {
						return $payload['successMessage'];
					}
				]
			],
			'mutateAndGetPayload' => function ($input, $context, $info) {
				if (!function_exists('wp_handle_sideload')) {
					require_once(ABSPATH . 'wp-admin/includes/file.php');
				}

				$file_return = wp_handle_sideload($input['file'], [
					'test_form' => false,
					'test_type' => false,
				]);

				if (isset($file_return['error']) || isset($file_return['upload_error_handler'])) {
					throw new \GraphQL\Error\UserError("The file could not be uploaded.");
				}
				
				$filename = $file_return['file'];

				$attachment = [
					'guid' => $file_return['url'], 
					'post_mime_type' => $file_return['type'],
					'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
					'post_content' => '',
					'post_status' => 'inherit'
				];

				$attachment_id = wp_insert_attachment($attachment, $filename);

				require_once(ABSPATH . 'wp-admin/includes/image.php');
				$attach_data = wp_generate_attachment_metadata($attachment_id, $filename);
				wp_update_attachment_metadata($attachment_id, $attach_data);

				update_field('profile_pic', $attachment_id, 'user_' . $current_user->ID);

				$profile_pic = get_field('profile_pic', 'user_' . $current_user->ID);
				$avatarUrl = $profile_pic['url'];
				$avatarUrlThumbnail = $profile_pic['sizes']['thumbnail'];

				return [
					'avatarUrl' => $avatarUrl,
					'avatarUrlThumbnail' => $avatarUrlThumbnail,
					'successMessage' => true,
				];
			}
		]);

Uploading it this way:

	const UPLOAD_IMAGE_MUTATION = gql`
                    mutation UploadProfilePicture($input: UploadProfilePictureInput!) {
                      uploadProfilePicture(input: $input) {
                        avatarUrl
                        avatarUrlThumbnail
                      }
                    }
                  `;
                
                const selectImage = async () => {
             
			// Check for the permission
              const permissionResult =
                await ImagePicker.requestMediaLibraryPermissionsAsync();
          
              if (permissionResult.granted === false) {
                alert("You've refused to allow this app to access your photos!");
                return;
              }
          
              // Open the image picker
              let pickerResult = await ImagePicker.launchImageLibraryAsync({
                mediaTypes: ImagePicker.MediaTypeOptions.Images,
                allowsEditing: true, // or false based on your requirement
                aspect: [4, 3], // aspect ratio
                quality: 1, // quality of the image
              });
          
              if (pickerResult.canceled === true) {
                return;
              }
          
              // Access the selected asset
              const selectedAsset = pickerResult.assets[0]; // Assuming single image selection
          
              if (selectedAsset) {
                const source = {
                  uri: selectedAsset.uri,
                  type: selectedAsset.type, // type is now part of the asset
                  name: selectedAsset.fileName || "profile-pic.jpg", // name can be accessed or set a default
                };
          
                console.log(source);
                uploadImage(source);
              } else {
                console.error("No image selected");
              }
            };
          
            const [uploadProfilePicture] = useMutation(UPLOAD_IMAGE_MUTATION);
          
            const uploadImage = async (imageFile) => {
              // Convert image file to a format suitable for GraphQL upload
              let localUri = imageFile.uri;
              let filename = localUri.split("/").pop();
          
              // Infer the type of the image
              let match = /\.(\w+)$/.exec(filename);
              let type = match ? `image/${match[1]}` : imageFile.type;
          
              // Prepare the formData
              const formData = new FormData();
              formData.append("file", { uri: localUri, name: filename, type });
          
              console.log("Form Data Prepared:", formData);
          
              try {
                console.log("Sending request to server");
                const response = await uploadProfilePicture({
                  variables: {
                    input: { file: imageFile }, // Modify here to match the GraphQL mutation
                  },
                });
          
                console.log("Response received:", response);
                // Extract the data from the response
                const { avatarUrl, avatarUrlThumbnail, successMessage } =
                  response.data.uploadProfilePicture;
                if (successMessage) {
                  console.log(successMessage); // Log or handle the success message as needed
                  // Update user context with new image URLs
                  setUserData({ avatarUrl, avatarUrlThumbnail });
                }
              } catch (error) {
                console.error("Error during image upload:", error);
                console.error("Error details:", error.networkError?.result || error);
              }
            };

The problem is am still getting this error:
ERROR Error during image upload: [ApolloError: Internal server error]
ERROR Error details: [ApolloError: Internal server error]

@justlevine
Copy link
Collaborator

I'd start with formData.append("file", { uri: localUri, name: filename, type });, since you need to feed it an actual File or Blob object.

Then fix your catch statement at the end (or add an error handler to your ApolloClient definition), so you can get the actual error data and not just the generic message and continue your debugging.

@DevelopMod
Copy link
Author

I do have an errorLink:


const errorLink = onError(({ graphQLErrors, networkError }) => {
  if (graphQLErrors)
    graphQLErrors.forEach(({ message, locations, path }) =>
      console.error(
        `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
      )
    );

  if (networkError) console.error(`[Network error]: ${networkError}`);
});

The thing is, am not getting the root of the error... Even tho, according to here, this should work in expo:
https://stackoverflow.com/questions/66372873/react-native-expo-post-blob#comment117341523_66372873


const uploadImage = async (imageFile) => {
    try {
      // Extract the file extension
      let fileType = imageFile.uri.substring(
        imageFile.uri.lastIndexOf(".") + 1
      );

      // Prepare the formData
      const formData = new FormData();
      formData.append("file", {
        uri: imageFile.uri,
        name: imageFile.name, // You can use a dynamic name based on the context
        type: `image/${fileType}`,
      });

      console.log("Form Data Prepared:", formData);

      console.log("Sending request to server");
      const response = await uploadProfilePicture({
        variables: {
          input: { file: formData }, // Modify here to match the GraphQL mutation
        },
      });

      console.log("Response received:", response);
      // Extract the data from the response
      const { avatarUrl, avatarUrlThumbnail, successMessage } =
        response.data.uploadProfilePicture;
      if (successMessage) {
        console.log(successMessage); // Log or handle the success message as needed
        // Update user context with new image URLs
        setUserData({ avatarUrl, avatarUrlThumbnail });
      }
    } catch (error) {
      console.error("Error during image upload:", error);
      if (
        error.networkError &&
        error.networkError.result &&
        error.networkError.result.errors
      ) {
        error.networkError.result.errors.forEach((e) =>
          console.error(e.message)
        );
      }
    }
  };

But I'm still getting:
LOG {"name": "profile-pic.jpg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FCudl-6de743e2-8e52-4646-b93f-9ed9ba6b740c/ImagePicker/60ced4f4-58f9-443c-ba72-27ad763aae27.jpeg"}
LOG Form Data Prepared: {"_parts": [["file", [Object]]]}
LOG Sending request to server
ERROR [GraphQL error]: Message: Internal server error, Location: [object Object], Path: undefined
ERROR Error during image upload: [ApolloError: Internal server error]

@dre1080
Copy link
Owner

dre1080 commented Nov 15, 2023

Since it's an Internal server error, try enabling WP_DEBUG and GRAPHQL_DEBUG to see more info and check the graphql response in your browser devtools since it might be a malformed response.

Add this to your wp-config.php:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('SCRIPT_DEBUG', true);
define('GRAPHQL_DEBUG', true);

@DevelopMod
Copy link
Author

DevelopMod commented Nov 15, 2023

Since it's an Internal server error, try enabling WP_DEBUG and GRAPHQL_DEBUG to see more info and check the graphql response in your browser devtools since it might be a malformed response.

Add this to your wp-config.php:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('SCRIPT_DEBUG', true);
define('GRAPHQL_DEBUG', true);

Thanks for your reply @dre1080 , sadly I have all of them enabled :


define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', true);
@ini_set('display_errors',1 );
define('SCRIPT_DEBUG', true);
define('GRAPHQL_DEBUG', true);

Also, just to make sure, I get no error I have added your sample upload mutation in the readme and tried to upload the image to it:


const SIMPLE_UPLOAD_MUTATION = gql`
  mutation UploadFile($input: UploadInput!) {
    upload(input: $input) {
      text
    }
  }
`;

const selectImage = async () => {
    // Check for the permission
    const permissionResult =
      await ImagePicker.requestMediaLibraryPermissionsAsync();

    if (permissionResult.granted === false) {
      alert("You've refused to allow this app to access your photos!");
      return;
    }

    // Open the image picker
    let pickerResult = await ImagePicker.launchImageLibraryAsync({
      mediaTypes: ImagePicker.MediaTypeOptions.Images,
      allowsEditing: true, // or false based on your requirement
      aspect: [4, 4], // aspect ratio
      quality: 1, // quality of the image
    });

    if (pickerResult.canceled === true) {
      return;
    }

    // Access the selected asset
    const selectedAsset = pickerResult.assets[0]; // Assuming single image selection

    if (selectedAsset) {
      const source = {
        uri: selectedAsset.uri,
        type: selectedAsset.type, // type is now part of the asset
        name: selectedAsset.fileName || "profile-pic.jpg", // name can be accessed or set a default
      };

      console.log(source);
      uploadImage(source);
    } else {
      console.error("No image selected");
    }
  };

const [uploadFileMutation] = useMutation(SIMPLE_UPLOAD_MUTATION);

const uploadImage = async (imageFile) => {
    const blob = await new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.onload = function () {
        resolve(xhr.response);
      };
      xhr.onerror = function (e) {
        console.log(e);
        reject(new TypeError("Network request failed"));
      };
      xhr.responseType = "blob";
      xhr.open("GET", imageFile.uri, true);
      xhr.send(null);
    });

    try {
      const response = await uploadFileMutation({
        variables: {
          input: { file: blob },
        },
      });

      console.log("File uploaded successfully:", response.data.upload.text);
    } catch (error) {
      console.error("Error uploading file:", error);
    }
  };


All I get back is:
LOG {"name": "profile-pic.jpg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FCudl-6de743e2-8e52-4646-b93f-9ed9ba6b740c/ImagePicker/c5930b63-c616-4b68-a965-657972e121cb.jpeg"}
ERROR [GraphQL error]: Message: Internal server error, Location: [object Object], Path: undefined
ERROR Error uploading file: [ApolloError: Internal server error]

@DevelopMod
Copy link
Author

Finally, I have got this error:


 LOG  {"name": "profile-pic.jpg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FCudl-6de743e2-8e52-4646-b93f-9ed9ba6b740c/ImagePicker/766861b2-99b5-4ad8-b588-9144a4eeed8a.jpeg"}
 LOG  {"_data":{"lastModified":0,"name":"766861b2-99b5-4ad8-b588-9144a4eeed8a.jpeg","size":722647,"offset":0,"type":"image/jpeg","blobId":"54ac845e-f2cf-4fa4-93b8-ad5f7a978a97","__collector":{}}}
 LOG  Sending request to server
 ERROR  [GraphQL error]: Message: Variable "$input" got invalid value {"_parts":[["file",{"_data":{"lastModified":0,"name":"766861b2-99b5-4ad8-b588-9144a4eeed8a.jpeg","size":722647,"offset":0,"type":"image\/jpeg","blobId":"54ac845e-f2cf-4fa4-93b8-ad5f7a978a97","__collector":[]}}]]}; Field "_parts" is not defined by type UploadProfilePictureInput., Location: [object Object], Path: undefined

@justlevine
Copy link
Collaborator

justlevine commented Nov 15, 2023

Did you try this yet? Maybe there's something off about whatever automagical transformation is happening.

I'd start with formData.append("file", { uri: localUri, name: filename, type });, since you need to feed it an actual File or Blob object.

@DevelopMod
Copy link
Author

Did you try this yet? Maybe there's something about whatever automagical transformation is happening.

I'd start with formData.append("file", { uri: localUri, name: filename, type });, since you need to feed it an actual File or Blob object.

yup, already tried to be honest. Not working .. Getting the same error, or similar errors invalid input.

@DevelopMod
Copy link
Author

Okay, the error disappeared or changed when tried this one:

const uploadImage = async (imageFile) => {
    try {
      const blob = await new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.onload = function () {
          resolve(xhr.response);
        };
        xhr.onerror = function (e) {
          console.log(e);
          reject(new TypeError("Network request failed"));
        };
        xhr.responseType = "blob";
        xhr.open("GET", imageFile.uri, true);
        xhr.send(null);
      });

      console.log(JSON.stringify(blob));

      const formData = new FormData();
      //formData.append("file", blob, imageFile.name);
      formData.append("userpic", blob, "chris1.jpg");

      // const test = {
      //   file: blob
      // };

      console.log("Sending request to server");
      const graphqlResponse = await uploadProfilePicture({
        variables: {
          input: { file: formData._parts[0].file }, // Modify here to match the GraphQL mutation
        },
      });

      console.log("Response received:", graphqlResponse);
      // Extract the data from the response
      const { avatarUrl, avatarUrlThumbnail, successMessage } =
        response.data.uploadProfilePicture;
      if (successMessage) {
        console.log(successMessage); // Log or handle the success message as needed
        // Update user context with new image URLs
        setUserData({ avatarUrl, avatarUrlThumbnail });
      }
    } catch (error) {
      console.error(
        "Error during image upload:",
        error.graphQLErrors[0].debugMessage
      );
      if (
        error.networkError &&
        error.networkError.result &&
        error.networkError.result.errors
      ) {
        error.networkError.result.errors.forEach((e) =>
          console.error(e.message)
        );
      }
    }
  };

 LOG  {"name": "profile-pic.jpg", "type": "image", "uri": "file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540anonymous%252FCudl-6de743e2-8e52-4646-b93f-9ed9ba6b740c/ImagePicker/ad852a20-7def-4d9c-a481-0718304cfe09.jpeg"}
 LOG  {"_data":{"lastModified":0,"name":"ad852a20-7def-4d9c-a481-0718304cfe09.jpeg","size":722647,"offset":0,"type":"image/jpeg","blobId":"d37a64c4-c314-4a49-9e56-2eaa54926960","__collector":{}}}
 LOG  Sending request to server
 ERROR  [GraphQL error]: Message: The file could not be uploaded., Location: [object Object], Path: uploadProfilePicture       
 ERROR  Error during image upload: undefined

@DevelopMod
Copy link
Author

so it only accepted my input when I tried the blob._data but still failed on server side :(


const uploadImage = async (imageFile) => {
    try {
      const blob = await new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.onload = function () {
          resolve(xhr.response);
        };
        xhr.onerror = function (e) {
          console.log(e);
          reject(new TypeError("Network request failed"));
        };
        xhr.responseType = "blob";
        xhr.open("GET", imageFile.uri, true);
        xhr.send(null);
      });

      const formData = new FormData();
      formData.append("userpic", blob, "chris1.jpg");

      console.log(blob._data);

      const graphqlResponse = await uploadProfilePicture({
        variables: {
          input: { file: blob._data }, // Modify here to match the GraphQL mutation
        },
      });

      // const graphqlResponse = await uploadFileMutation({
      //   variables: {
      //     input: { file: formData._parts[0][1]._data },
      //   },
      // });

      console.log("Response received:", graphqlResponse);
      const { avatarUrl, avatarUrlThumbnail, successMessage } =
        response.data.uploadProfilePicture;
      if (successMessage) {
        console.log(successMessage);
        setUserData({ avatarUrl, avatarUrlThumbnail });
      }
    } catch (error) {
      console.error(
        "Error during image upload:",
        error.graphQLErrors[0].debugMessage
      );
      console.error("Error during image upload:", error);
    }
  };

Here the error log :


[15-Nov-2023 17:26:28 UTC] Received file: Array
(
    [lastModified] => 0
    [name] => 13436d64-b9c0-46a1-a375-e0b049b396c0.jpeg
    [size] => 722647
    [offset] => 0
    [type] => image/jpeg
    [blobId] => a5ead176-e0c4-4714-a700-fb475ebf7fcc
    [__collector] => Array
        (
        )

    [tmp_name] => /tmp/13436d64-b9c0-46a1-a375-e0b049b396c0.jpeg
)

[15-Nov-2023 17:26:28 UTC] uploadProfilePicture mutation called
[15-Nov-2023 17:26:28 UTC] Handling file upload
[15-Nov-2023 17:26:28 UTC] File upload error: {"error":"Specified file failed upload test."}

@justlevine
Copy link
Collaborator

That error comes from WP's handle_file_upload().

I've run into something similar myself in the past over in #2 , was able to get around it by using wp_upload_bits() on the server side, since that doesn't rely on the is_file_uploaded() check that seems to be failing.

@DevelopMod
Copy link
Author

After using wp_upload_bits it most likely fails to upload the image or the photo.. and save a photo with 0 byte in the uplaod dir:

Code:


register_graphql_mutation('uploadProfilePicture', [
			'inputFields' => [
				'file' => [
					'type' => 'Upload',
				],
			],
			'outputFields' => [
				'avatarUrl' => [
					'type' => 'String',
					'resolve' => function ($payload) {
						return $payload['avatarUrl'];
					}
				],
				'avatarUrlThumbnail' => [
					'type' => 'String',
					'resolve' => function ($payload) {
						return $payload['avatarUrlThumbnail'];
					}
				],
				'successMessage' => [
					'type' => 'Boolean',
					'resolve' => function ($payload) {
						return $payload['successMessage'];
					}
				]
			],
			'mutateAndGetPayload' => function ($input, $context, $info) {		

				$upload = wp_upload_bits($input['file']['name'], null, file_get_contents($input['file']['tmp_name']));
				
				if (!$upload['error']) {
					error_log('Upload: ' . print_r($upload, true));
					$filename = $upload['file'];
					
					$attachment = [
						'guid' => $file_return['url'], 
						'post_mime_type' => $file_return['type'],
						'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
						'post_content' => '',
						'post_status' => 'inherit'
					];

					$attachment_id = wp_insert_attachment($attachment, $filename);

					require_once(ABSPATH . 'wp-admin/includes/image.php');
					$attach_data = wp_generate_attachment_metadata($attachment_id, $filename);
					wp_update_attachment_metadata($attachment_id, $attach_data);

					update_field('profile_pic', $attachment_id, 'user_' . $current_user->ID);

					$profile_pic = get_field('profile_pic', 'user_' . $current_user->ID);
					$avatarUrl = $profile_pic['url'];
					$avatarUrlThumbnail = $profile_pic['sizes']['thumbnail'];

					return [
						'avatarUrl' => $avatarUrl,
						'avatarUrlThumbnail' => $avatarUrlThumbnail,
						'successMessage' => true,
					];
				} else {
					error_log('File upload error: ' . $upload['error']);
					throw new \GraphQL\Error\UserError("The file could not be uploaded.");
				}
				
			}
		]);

Log:


[15-Nov-2023 18:25:33 UTC] PHP Warning:  file_get_contents(/tmp/photo.jpeg): Failed to open stream: No such file or directory in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 404
[15-Nov-2023 18:25:33 UTC] Upload: Array
(
    [file] => /home/**PATH**/wp-content/uploads/2023/11/photo-2.jpeg
    [url] => https://testDomain/wp-content/uploads/2023/11/photo-2.jpeg
    [type] => image/jpeg
    [error] => 
)

[15-Nov-2023 18:25:33 UTC] PHP Warning:  Undefined variable $file_return in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 411
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Trying to access array offset on value of type null in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 411
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Undefined variable $file_return in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 412
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Trying to access array offset on value of type null in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 412
[15-Nov-2023 18:25:33 UTC] PHP Deprecated:  preg_replace(): Passing null to parameter #3 ($subject) of type array|string is deprecated in /home/**PATH**/wp-includes/formatting.php on line 5725
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Undefined variable $current_user in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 424
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Attempt to read property "ID" on null in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 424
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Undefined variable $current_user in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 426
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Attempt to read property "ID" on null in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 426
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Undefined array key "sizes" in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 428
[15-Nov-2023 18:25:33 UTC] PHP Warning:  Trying to access array offset on value of type null in /home/**PATH**/wp-content/themes/headless-xfive/functions.php on line 428

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants