Skip to main content

Troubleshooting

API errors by HTTP status​

Every error response is JSON. Most endpoints return { "status": false, "error": "<message>" }. The Shareholders endpoint returns { "error": "<label>", "message": "<message>" } for its 400, 403 and 500 responses.

StatusReturned byWhat it meansWhat to check
400All endpointsThe request was rejected before processing. The error text names the field or rule.Token: client_id and client_secret are both present. Events: recordDate and pastRecordDate are YYYY-MM-DD, pastRecordDate is not a future date, limit is 25 or less, at most 15 CUSIPs, ISINs or tickers. Event details and Voting URL: eventId and brokerId are 24-character hex IDs. Voting URL: accountNo and brokerId are both present, and you are not passing email. Shareholders and Trades: the field named in the message.
401All endpointsOn the token endpoint, the credentials were rejected. On every other endpoint, the Bearer token is missing, expired or invalid. The body is always Authorization header is required, whatever the cause.You are sending Authorization: Bearer <token>. The token was issued for the environment you are calling. You refresh it before expires_in elapses.
403Shareholders, Voting URLShareholders: the reporting deadline for this event has passed. Voting URL: brokerId is not the broker the shareholder was submitted under.Shareholders: check shareholderReportingDeadline on the event and submit on the evening of the record date. Voting URL: use the same brokerId you used in the shareholders request.
404Event details, Voting URLEvent details: no event with that ID. Voting URL: no event with that ID, the event is not a Proxy event, or accountNo was not submitted for this event.The eventId comes from the Events list. The account number is exactly the value you submitted. The event's eventType is Proxy.
423Voting URLVoting is not open. Either final documents are not confirmed yet ("Voting URL Not Active") or the voting period has ended.Call Event details first and only show "Vote Now" when votingLinksActive is true.
429All endpointsThe AWS API gateway rate limit was hit: 5,000 requests per 5 minutes per IP address across all /broker/v1 routes.Back off and retry. Spread bulk work across the window.
500All endpointsAn unexpected server error.Retry with backoff. If it persists, contact the VOTR team with the endpoint, timestamp and request body.

Authentication Issues​

"Invalid client credentials" error

  • OAuth API returns 401 or 403 error.
  • Authentication fails.
  • Verify Client ID and Client Secret are correct.
  • Ensure no extra spaces or characters.
  • Confirm credentials are stored securely on your backend.
  • Verify you're using the correct environment URL.
  • Contact the VOTR team to verify credentials.

Token expiration errors

  • API calls work initially but start failing with 401 after a while.
  • Access token has expired error messages.

Tokens expire after the number of seconds returned in expires_in. Cache the token and refresh it before that elapses:

auth.ts — cache + refresh
const getValidToken = async () => {
const now = Date.now();

if (cachedToken && cachedToken.expires > now) {
return cachedToken.access_token;
}

const newToken = await getOAuthToken();
cachedToken = {
access_token: newToken.access_token,
expires: now + newToken.expires_in * 1000,
};

return cachedToken.access_token;
};

API Issues​

"Account number not found for this event" error

  • The voting URL request returns 404 even though the shareholder was submitted.
  • The voting URL request returns 403 "Shareholder does not belong to the specified broker".
  • Check that accountNo is exactly the value you submitted in the shareholders request for this event. The lookup is an exact match.
  • Check that brokerId is the same broker ID you submitted the shareholder under. A mismatch returns 403.
  • Check the eventId is the event the shareholder was submitted for.
  • Confirm the shareholders submission for this event was accepted (202) before the reporting deadline.

Network request failing

  • API calls timeout or fail.
  • Connection errors.
  • Check internet connectivity.
  • Verify the base URL — Development https://api-stage.govotr.com/broker/v1, Production https://server.govotr.com/broker/v1.
  • Ensure proper headers are included.
  • Implement retry logic for network failures (see code below).
fetchWithRetry.ts — exponential backoff
const fetchWithRetry = async (url: string, options: any, retries = 3) => {
for (let i = 0; i < retries; i++) {
try {
const response = await fetch(url, options);
return response;
} catch (error) {
if (i === retries - 1) throw error;
await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));
}
}
};

SDK Installation Issues​

"Module not found" error after SDK installation​

Terminal — clear cache and reinstall
# Clear npm cache and reinstall
npm cache clean --force
rm -rf node_modules package-lock.json
npm install
npm install ./govotr-vote-react-native-1.0.0.tgz --legacy-peer-deps

Peer dependency warnings​

The --legacy-peer-deps flag is required for this package. This is normal and expected.

TypeScript errors​

The SDK ships its own type definitions, which reference types from react and react-native. React Native 0.71 and later bundles its own types, so do not install @types/react-native. The only type package you need is @types/react, which every TypeScript React Native project already has. If it is missing:

Terminal — add React type defs
npm install @types/react --save-dev

SDK Component Issues​

WebView not opening or blank screen

  • Button press doesn't open voting interface.
  • Blank white screen appears.
  • Modal opens but no content.
  • Check that the voting URL is valid and not empty.
  • Verify the URL format is correct (should contain ID).
  • Test with a known working URL.
  • Check the console for JavaScript errors.
  • Ensure WebView has proper permissions in your app.
VoteButton.tsx — log the URL
console.log("Voting URL:", votingUrl);
console.log("URL is valid:", votingUrl && votingUrl.length > 0);

Button not responding to press

  • Button appears but doesn't respond to taps.
  • No console logs from onPress handler.
  • Check whether the button is disabled: isDisabled={false}.
  • Verify onPress is defined.
  • Check for overlapping views that may intercept touches.
  • Ensure button has proper dimensions.
VoteButton.tsx — minimum tap target
<VoteNowButton
URL={votingUrl}
isDisabled={false}
onPress={() => console.log("Button pressed")}
buttonStyle={{
minHeight: 44,
minWidth: 200,
}}
/>

Modal / WebView crashes or freezes

  • App crashes when voting modal opens.
  • WebView becomes unresponsive.
  • Memory issues during voting.
  • Implement proper cleanup on component unmount.
  • Add error boundaries around the SDK component.
  • Monitor memory usage during development.
VoteButton.tsx — unmount cleanup
useEffect(() => {
return () => {
setVotingUrl("");
};
}, []);

Error Handling Patterns​

SDK error types​

VoteButton.tsx — map SDK errors to user messages
<VoteNowButton
URL={votingUrl}
onError={(error) => {
console.error("SDK Error:", error);

let userMessage = "An unexpected error occurred during voting.";

if (error.includes("network")) {
userMessage = "Network connection lost. Please check your internet connection.";
} else if (error.includes("timeout")) {
userMessage = "Voting session timed out. Please try again.";
} else if (error.includes("permission")) {
userMessage = "You do not have permission to access this voting session.";
} else if (error.includes("invalid_token")) {
userMessage = "Your voting session has expired. Please try again.";
} else if (error.includes("already_voted")) {
userMessage = "You have already submitted your vote for this event.";
}

Alert.alert("Voting Error", userMessage);
setVotingUrl("");
}}
/>

API error handling​

handleApiError.ts — status-aware error helper
const handleApiError = (error: any, context: string) => {
console.error(`${context} error:`, error);

if (error.response) {
const status = error.response.status;
const message = error.response.data?.message || "Unknown error";

switch (status) {
case 401:
return "Authentication failed. Please check your credentials.";
case 403:
return "You don't have permission to perform this action.";
case 404:
return "The requested resource was not found.";
case 500:
return "Server error. Please try again later.";
default:
return `Error ${status}: ${message}`;
}
} else if (error.request) {
return "Network error. Please check your internet connection.";
} else {
return `Unexpected error: ${error.message}`;
}
};

Performance Tips​

Token caching​

tokenCache.ts — reuse OAuth tokens until expiry
const tokenCache = { token: null, expires: 0 };

const getCachedToken = async () => {
if (tokenCache.token && Date.now() < tokenCache.expires) {
return tokenCache.token;
}

const response = await getOAuthToken();
tokenCache.token = response.access_token;
tokenCache.expires = Date.now() + response.expires_in * 1000;

return tokenCache.token;
};

Loading states​

VoteScreen.tsx — disable button while loading
const [isLoading, setIsLoading] = useState(false);

<VoteNowButton
URL={votingUrl}
isDisabled={isLoading || !votingUrl}
label={isLoading ? "Loading..." : "Vote Now"}
/>;

Getting Additional Help​

Development Resources​

Contact Support​

When contacting support, please include:

  1. Error messages (exact text).

  2. Console logs (if available).

  3. SDK version (1.0.0).

  4. Platform (React Native / React).

  5. Environment (Development / Production).

  6. Steps to reproduce the issue.

Debug Checklist​

Before reporting issues, verify:

Pre-flight checks
0 / 9

If you're still experiencing issues, contact the VOTR team with your specific error details and logs.