Amplify-js: Predictions - InvalidS3ObjectException

Created on 25 Apr 2020  Â·  9Comments  Â·  Source: aws-amplify/amplify-js

Env : React-native
"aws-amplify": "^3.0.8",
"aws-amplify-react-native": "^4.0.4",
"react": "16.11.0",
"react-native": "0.62.2",

Predictions configuration for Amplify.configure() :
predictions: {
identify: {
identifyText: {
proxy: false,
region: "us-east-1",
defaults: {
format: "ALL"
}
}
}

Issue :
When I user Predictions with S3 object, it returns an InvalidS3ObjectException.
"Unable to get object metadata from S3"
However when I use Storage on the same file, everything works fine.

My code - pretty simple :

 await Predictions.identify({
      text: {
        source: {
          key: "myFile.jpeg",
          level: "public"
        },
        format: "PLAIN"
      }
    })
      .then((res) => setPrediction(JSON.stringify(res, null, 2)))
      .catch((err) =>
        setPrediction("Predictions error : " + JSON.stringify(err, null, 2))
      );
  }

My succeeded Storage code :

Storage.get("myFile.jpeg") .then((res) => setPrediction(JSON.stringify(res, null, 2))) .catch((err) => "Storage error : " + JSON.stringify(err, null, 2));

Predictions React Native

All 9 comments

facing same issue.

error is here: https://github.com/aws-amplify/amplify-js/blob/14f1ef9b88bc5cb99ec0a47308d3fb9cf4c89102/packages/predictions/src/Providers/AmazonAIIdentifyPredictionsProvider.ts#L86

this is using URL encoded strings that are then past as the Body of a POST request. causes an issue with the identityId part that is like so: us-east-1:a-b-c-d. In url encoded form appears as us-east-1%3Aa-b-c-d; which is sent to Rekognition and is an invalid key.

also makes me wonder why the check at https://github.com/aws-amplify/amplify-js/blob/14f1ef9b88bc5cb99ec0a47308d3fb9cf4c89102/packages/predictions/src/Providers/AmazonAIIdentifyPredictionsProvider.ts#L81 is needed? if user does not have access to the file, an error would simply get returned from Rekognition service and yield same result.

a (naive?) implementation that fixes this:

res({
    S3Object: {
        Bucket: parsedURL[1],
        Name: `${source.level}/${source.identityId}/${source.key}`,
    },
});

Thanks @onlybakam

I tried your maybe naive implementation, and also directly forced Bucket and Name params, but unfortunately it won't work for me.

yeah. i think our use case is a bit different. i'm using a protected folder which means the identityId is part of the URL. this causes a problem in my situation.
In your case you have a "public" file so the URL will be a bit different (/public/).

i guess one question is: are you sure the file is at the specified location? you can check the payload of the Rekognition request to check was is being sent out.

I think you're right we have different issues. Actually my exemple is based on public folder but I tried also with a protected one. And files are in specified location because get Storage requests work fine.

But the think I noticed with Rekognition request is that S3 region isn't sent in payload. Bucket and name are good but no region. And in my case S3 is located in "eu-central-1" and Rekognition in "us-east-1" because of default Predictions settings.
Maybe is there a lead to follow.

Ok, there is indeed a region problem. I changed the Predictions one for the same as S3. And it worked with public folder. But @onlybakam as you mentioned with private or protected folder it failed.
The recognition request has the same issue in url : % as : between region and Identity.

So it seems we have two possible improvements :
Predictions settings should have the same region as Storage settings.
S3Object Url send to Recognition (or event Textract) should be corrected.

Ok, I just had a look, and it seems like @mlafo and @onlybakam are right, this issue describes two different "problems" that both cause an InvalidS3ObjectException:

  1. Rekognition / Textract and S3 have to be in the same region.
  2. The S3Object name, extracted from the object URL, is still percent-encoded.

While the first "problem" seems to be by design, the second one describes a bug that should be an easy fix by decoding parsedURL[2]:

res({ S3Object: { Bucket: parsedURL[1], Name: decodeURIComponent(parsedURL[2]) } });

decodeURIComponent replaces the %3A with the corresponding character (:), while the rest of the object name will stay as-is.

@mlafo @onlybakam – #6129 was merged and is now available at aws-amplify@unstable. I'd appreciate it if you could give it a try and see if this fixes your issue.

_If you do, please make sure Predictions and S3 are in the same region_

@cedricgrothues - I gave a try in eu-west-1 region.
It's fixed. Predictions works with private and protected Storage.
Thank a lot.

Glad it works, thanks for giving it a try!

Was this page helpful?
0 / 5 - 0 ratings