Compare commits

...

3 Commits

Author SHA1 Message Date
Claude
5373ca9012 [AI] Reset loadingSimpleFinAccounts before early return in INVALID_ACCESS_TOKEN branch
The early return for INVALID_ACCESS_TOKEN skipped the
setLoadingSimpleFinAccounts(false) call at the end of the handler,
leaving the spinner active and clicks disabled.

https://claude.ai/code/session_01CmcFHWUhqo3eC2joAWrtWM
2026-03-13 20:21:07 +00:00
github-actions[bot]
42ce174fc9 Add release notes for PR #7192 2026-03-13 20:16:03 +00:00
Claude
512049376f [AI] Improve SimpleFIN error handling with specific error messages
The SimpleFIN error flow was swallowing useful error details at three
points: the sync server sent a generic message, the client core
mislabeled all errors as TIMED_OUT, and the frontend silently bounced
users to the init modal without showing any error.

- Classify errors in serverDown() (Forbidden, invalid key, parse error,
  network failure) instead of sending a generic message
- Handle Forbidden errors in /accounts handler same as /transactions
- Distinguish timeout from other PostError types in simpleFinAccounts()
- Show error notification to user instead of silently redirecting
- Only redirect to init modal for INVALID_ACCESS_TOKEN errors

https://claude.ai/code/session_01CmcFHWUhqo3eC2joAWrtWM
2026-03-13 19:47:48 +00:00
4 changed files with 69 additions and 11 deletions

View File

@@ -85,8 +85,24 @@ export function CreateAccountModal({
try {
const results = await send('simplefin-accounts');
if (results.error_code === 'INVALID_ACCESS_TOKEN') {
setLoadingSimpleFinAccounts(false);
dispatch(
pushModal({
modal: {
name: 'simplefin-init',
options: {
onSuccess: () => setIsSimpleFinSetupComplete(true),
},
},
}),
);
return;
}
if (results.error_code) {
throw new Error(results.reason);
throw new Error(
results.reason || `SimpleFIN error: ${results.error_code}`,
);
}
const newAccounts = [];
@@ -127,12 +143,12 @@ export function CreateAccountModal({
} catch (err) {
console.error(err);
dispatch(
pushModal({
modal: {
name: 'simplefin-init',
options: {
onSuccess: () => setIsSimpleFinSetupComplete(true),
},
addNotification({
notification: {
type: 'error',
title: t('Error when trying to contact SimpleFIN'),
message: (err as Error).message || t('An unknown error occurred.'),
timeout: 10000,
},
}),
);

View File

@@ -746,8 +746,20 @@ async function simpleFinAccounts() {
},
60000,
);
} catch {
return { error_code: 'TIMED_OUT' };
} catch (error) {
if (error instanceof PostError && error.reason === 'network-failure') {
return {
error_code: 'TIMED_OUT',
reason: 'Request timed out or the sync server could not be reached.',
};
}
return {
error_code: 'REQUEST_FAILED',
reason:
error instanceof PostError
? `Sync server error: ${error.reason}`
: 'An unexpected error occurred.',
};
}
}

View File

@@ -63,7 +63,11 @@ app.post(
},
});
} catch (e) {
serverDown(e, res);
if (e.message === 'Forbidden') {
invalidToken(res);
} else {
serverDown(e, res);
}
return;
}
}),
@@ -279,13 +283,33 @@ function invalidToken(res) {
function serverDown(e, res) {
console.log(e);
let detail = 'There was an error communicating with SimpleFIN.';
if (e.message === 'Forbidden') {
detail =
'SimpleFIN rejected the request (403 Forbidden). Your access key may be expired.';
} else if (e.message === 'Invalid access key') {
detail =
'The SimpleFIN access key format is invalid. Please reset and re-enter your credentials.';
} else if (e instanceof SyntaxError) {
detail =
'SimpleFIN returned an invalid response. The service may be temporarily unavailable.';
} else if (
e.cause?.code === 'ENOTFOUND' ||
e.cause?.code === 'ECONNREFUSED' ||
e.message?.includes('fetch failed')
) {
detail = 'Could not connect to SimpleFIN server.';
}
res.send({
status: 'ok',
data: {
error_type: 'SERVER_DOWN',
error_code: 'SERVER_DOWN',
status: 'rejected',
reason: 'There was an error communicating with SimpleFIN.',
reason: detail,
},
});
}

View File

@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [MatissJanis]
---
Improve SimpleFIN error handling with specific notifications and context-aware messages for users.