phacility/phabricator · error · PhabricatorWorkerPermanentFailureException
Unable to find any Asana user with valid credentials to pull
Error message
Unable to find any Asana user with valid credentials to pull an OAuth token out of.
What it means
To post to Asana the worker needs an OAuth token; it tries the story author first, then every user with a linked Asana account (findAnyValidAsanaAccessToken()). If none of them yield a usable token, PhabricatorWorkerPermanentFailureException is thrown and the story task is permanently dropped. Unlike error 529, linkage exists here — the tokens themselves are missing, expired, or revoked.
Source
Thrown at src/applications/doorkeeper/worker/DoorkeeperAsanaFeedWorker.php:88
$owner_asana_id = idx($phid_aid_map, $owner_phid);
$all_asana_ids = array_select_keys($phid_aid_map, $all_phids);
$all_asana_ids = array_values($all_asana_ids);
// Even if the actor isn't a reviewer, etc., try to use their account so
// we can post in the correct voice. If we miss, we'll try all the other
// related users.
$try_users = array_merge(
array($data->getAuthorPHID()),
array_keys($phid_aid_map));
$try_users = array_filter($try_users);
$access_info = $this->findAnyValidAsanaAccessToken($try_users);
list($possessed_user, $possessed_asana_id, $oauth_token) = $access_info;
if (!$oauth_token) {
throw new PhabricatorWorkerPermanentFailureException(
pht(
'Unable to find any Asana user with valid credentials to '.
'pull an OAuth token out of.'));
}
$etype_main = PhabricatorObjectHasAsanaTaskEdgeType::EDGECONST;
$etype_sub = PhabricatorObjectHasAsanaSubtaskEdgeType::EDGECONST;
$equery = id(new PhabricatorEdgeQuery())
->withSourcePHIDs(array($src_phid))
->withEdgeTypes(
array(
$etype_main,
$etype_sub,
))
->needEdgeData(true);
$edges = $equery->execute();View on GitHub (pinned to 5720a38cfe)
Solutions
- Verify asana.application-id and application-private-key config match the Asana developer app
- Have the affected users unlink and re-link Asana under Settings -> External Accounts to mint fresh tokens
- Check daemons log (`bin/phd log`) for the underlying token-refresh errors
- After re-linking, generate a new story on the object to re-queue publishing
Defensive patterns
Strategy: fallback
Validate before calling
// Pre-flight: confirm a usable Asana OAuth token exists before queueing the story.
list($user, $id, $token) = $this->findAnyValidAsanaAccessToken($try_users);
if (!$token) {
// Queue a re-link notification instead of a publish task that will permanent-fail.
return;
} Prevention
- Keep asana.application-id / application-private-key in sync with the Asana developer app
- Ask users to re-link Asana after any OAuth app secret rotation
- Distinguish this from error 529: accounts are linked here, tokens are the problem
When it happens
Trigger: All related users have Asana accounts linked, but every stored OAuth token fails validation (expired refresh tokens, revoked grants, app secret changed, or tokens never obtained because the provider credentials are wrong).
Common situations: Asana OAuth application secret rotated or misconfigured (asana.application-id / application-private-key), so refresh fails; users who linked long ago and revoked access; password/secret typos in the Phabricator Asana provider config causing silent token-refresh failure.
Related errors
- No related users have linked Asana accounts.
- Synchronization of parent task from Asana failed!
- %s has no visible object on the other side; this likely indi
- Synchronization of child task from Asana failed!
- No Asana provider configured.
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/19fa0da4278c7bd0.
Report an issue: GitHub.