facebookarchive / php-graph-sdk

The Facebook SDK for PHP provides a native interface to the Graph API and Facebook Login. https://developers.facebook.com/docs/php
Other
3.18k stars 1.96k forks source link

Failed to get report from facebook api with Status 400 and error code 2601 #1094

Open JenyaInfiapps opened 5 years ago

JenyaInfiapps commented 5 years ago

I got the error: "Sorry, the report cannot be loaded successfully. Please check if your job status is completed instead of failed or running before fetching the data."

In some report dates, it is ok, there is no error. But on other dates, I got the error.

I haven't found about this error anything on facebook/google search.. So, what is the problem? Expecting your feedback. Thanks!

The response that I get is:

Message: Call was not successful Method: GET Path: https://graph.facebook.com/v3.0/xxxxxxxxxxxxxx/insights Params: {}

Status: 400 Response: { "error": { "code": 2601, "is_transient": true, "error_subcode": 1815107, "error_user_msg": "Sorry, the report cannot be loaded successfully. Please check if your job status is completed instead of failed or running before fetching the data.", "error_user_title": "Loading Async Ads Report Failed", "message": "Error accessing adreport job.", "type": "OAuthException", "fbtrace_id": "xxxxxxxx" } }

jiajie-chen commented 5 years ago

I have been getting a similar issue with the php-business-sdk.

Using the code sample from Facebook:

// Source: https://developers.facebook.com/docs/marketing-api/insights/best-practices/#asynchronous
// Note: the python business sdk code sample has the same issue
$async_job = $campaign->getInsightsAsync(array(), $params);

$async_job->read();

while (!$async_job->isComplete()) {
  sleep(1);
  $async_job->read();
}

$async_job->getInsights();

I get an AuthorizationException with code 2601 and message "Error accessing adreport job."

The issue was in FacebookAds\Object\AdReportRun::isComplete

public function isComplete() {
  return $this->{AdReportRunFields::ASYNC_PERCENT_COMPLETION} === 100;
}

There's an edge case where an async insight run can have 100% completion but still have the "Job Running" status. If you only check for 100% completion, you'll get a 2601 error if the status is still "Job Running".

The following code works for me:

$async_job = $campaign->getInsightsAsync(array(), $params);

$async_job->read();

while (!$async_job->isComplete() && $async_job->async_status !== 'Job Running') {
  sleep(1);
  $async_job->read();
}

$async_job->getInsights();

I sent a bug report to Facebook on this issue here.

TL;DR: Check the values of async_percent_completion and async_status before attempting to read from <AD_REPORT_ID>/insights

JenyaInfiapps commented 5 years ago

TL;DR: Check the values of async_percent_completion and async_status before attempting to read from <AD_REPORT_ID>/insights

hi!

Thank you for the response, but I am tried to add code that also checks that job not running but it not solve it.. still get error

jiajie-chen commented 5 years ago

I can't say for certain why you're getting the error. It could be that your jobs are failing or otherwise not successfully completing, which will cause issues when calling $async_job->getInsights();

Based on the Facebook documentation, a job can be completed, failed, or skipped. I assume that reading the insights of a skipped or failed job is causing your error.

You would need to check the job status is completed before getting the insights:

if ($async_job->async_status === 'Job Completed') {
  $async_job->getInsights();
} else {
  // error handling or logging code goes here
}
incady commented 5 years ago

The "isComplete" will be true, and it'll break out of the while loop while the async_status is still "Job Running." I think it should be:

while (!$async_job->isComplete()) { sleep(1); $async_job->read(); }

while ($async_job->async_status === 'Job Running' || $async_job->async_status === 'Job Not Started')) { sleep(1); $async_job->read(); }

jiajie-chen commented 5 years ago

@incady Thanks for catching that! I made a typo in the original fix, the logic should've been !($async_job->isComplete() && $async_job->async_status !== 'Job Running') or !$async_job->isComplete() || $async_job->async_status === 'Job Running'

A complete example should be:

$async_job = $campaign->getInsightsAsync(array(), $params);

// using a do-while loop instead to avoid code duplication
do {
  sleep(1);
  $async_job->read();
} while (
  // keep checking if job not completed
  !$async_job->isComplete() ||
  // or job status is still running
  $async_job->async_status === 'Job Running' ||
  // or job status is not started
  $async_job->async_status === 'Job Not Started'
);

if ($async_job->async_status === 'Job Completed') {
  $async_job->getInsights();
} elseif ($async_job->async_status === 'Job Skipped') {
  // retry handling
} else {
  // error handling
}

As an aside, I've also noticed that sometimes a job will get stuck at 0% completion and Job Not Started status indefinitely. So there would need to be some logic to check if a job's stuck and exit the while loop.

seeni-dev commented 5 years ago

From the comment by @jiajie-chen , There's an edge case where an async insight run can have 100% completion but still have the "Job Running" status. If you only check for 100% completion, you'll get a 2601 error if the status is still "Job Running".. It fixed the issue for me.