actualbudget/actual · error · RequisitionNotLinked
Requisition not linked yet
Error message
Requisition not linked yet
What it means
gocardless-service fetches a requisition and only continues when its status is 'LN' (linked), meaning the end user finished the bank authorization. Any other status throws RequisitionNotLinked carrying the actual requisitionStatus.
Source
Thrown at packages/sync-server/src/app-gocardless/services/gocardless-service.ts:144
}
};
if (isExpiredJwtToken(getGocardlessClient().token)) {
await client.generateToken().catch(handleGoCardlessError);
}
},
getLinkedRequisition: async (
requisitionId: GoCardlessRequisitionId,
): Promise<Requisition> => {
const requisition = await goCardlessService.getRequisition(requisitionId);
const { status } = requisition;
// Continue only if status of requisition is "LN" which
// means the account has been successfully linked to the requisition
if (status !== 'LN') {
throw new RequisitionNotLinked({ requisitionStatus: status });
}
return requisition;
},
getRequisitionWithAccounts: async (
requisitionId: GoCardlessRequisitionId,
): Promise<{
requisition: Requisition;
accounts: NormalizedAccountDetails[];
}> => {
const requisition =
await goCardlessService.getLinkedRequisition(requisitionId);
console.log('GoCardless requisition linked:', {
institutionId: requisition.institution_id,
requisitionId,
agreementId: requisition.agreement,View on GitHub (pinned to d4334cb6e6)
Solutions
- Have the user re-run the link flow (create a new requisition and complete bank authorization) to reach status LN
- Inspect the returned requisitionStatus to decide the message shown to the user (expired vs rejected vs pending)
- If status is CR, send the user to the requisition link URL to finish authorization
- Delete the stale requisition/account in the UI and re-add the bank connection
Example fix
// before
const accounts = await gocardlessService.getRequisitionWithAccounts(reqId); // throws if not LN
// after
const req = await gocardlessService.getRequisition(reqId);
if (req.status !== 'LN') {
// prompt user to re-authenticate / re-create the link
await restartLinkFlow(institutionId);
return;
}
const accounts = await gocardlessService.getRequisitionWithAccounts(reqId); Defensive patterns
Strategy: try-catch
Try / catch
try {
const requisition = await getRequisition(reqId);
} catch (e) {
if (e instanceof RequisitionNotLinked) {
switch (e.details?.requisitionStatus) {
case 'CR': promptUserToFinishBankAuth(e.details.link); break;
case 'EX': case 'RJ': case 'GC':
default: await recreateRequisition(institutionId); // re-link flow
}
} else throw e;
} Prevention
- Only query accounts after the user completes the bank authorization redirect
- Check requisition status before polling and surface pending states in the UI
- Expect 90-day consent expiry and plan periodic re-linking
- Persist the requisition link URL so users can resume an interrupted authorization
When it happens
Trigger: Polling/reading accounts for a requisition whose status is e.g. 'RJ' (rejected/suspended), 'EX' (expired), 'CR' (created but not yet continued), or 'GC' (cancelled) — i.e. the user never completed (or failed) the bank consent flow.
Common situations: User closed the bank auth window without approving; bank rejected the PSU or the consent expired; server tried to sync a bank connection before the user finished linking; requisition link expired after 90 days per GoCardless.
Related errors
- Account with ID ${upgradingId} not found.
- Provided account id is not linked to given requisition
- ITEM_LOGIN_REQUIRED
- res.error_code
- response.reason || response.error_code
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/0b5b7b8962335405.
Report an issue: GitHub.