Stirling-Tools/Stirling-PDF · error · Error

Failed to submit signature

Error message

Failed to submit signature

What it means

Thrown by submitSignature() in useParticipantSession after workflowService.submitSignature (or the subsequent loadSession reload) rejects. The hook first tries to extract a usable message: axios errors use response.data.message, other Errors use err.message, and only if neither exists does it fall back to 'Failed to submit signature'. The thrown Error carries the original as {cause} and the same string is set into the error state for UI.

Source

Thrown at frontend/editor/src/proprietary/hooks/workflow/useParticipantSession.ts:72

  const submitSignature = useCallback(
    async (request: SignatureSubmissionRequest) => {
      setLoading(true);
      setError(null);
      try {
        const updatedParticipant =
          await workflowService.submitSignature(request);
        setParticipant(updatedParticipant);
        // Reload session to get updated status
        if (request.participantToken) {
          await loadSession(request.participantToken);
        }
      } catch (err: unknown) {
        const errorMsg = isAxiosError(err)
          ? err.response?.data?.message || err.message
          : (err instanceof Error ? err.message : undefined) ||
            "Failed to submit signature";
        setError(errorMsg);
        throw new Error(errorMsg, { cause: err });
      } finally {
        setLoading(false);
      }
    },
    [loadSession],
  );

  const decline = useCallback(
    async (token: string, reason?: string) => {
      setLoading(true);
      setError(null);
      try {
        const updatedParticipant = await workflowService.declineParticipation(
          token,
          reason,
        );
        setParticipant(updatedParticipant);
        // Reload session

View on GitHub (pinned to 9ef20dcab8)

Solutions

  1. Check the axios response status/message shown in error state — it usually carries the real backend reason.
  2. Ensure SignatureSubmissionRequest has a valid participantToken and all required signature fields before submitting.
  3. Handle the thrown error at the call site (it re-throws after setting state) and surface the backend message to the user.
  4. If the token expired, re-issue/re-fetch the participant link rather than retrying the same request.

Example fix

// before
try { await submitSignature(req); } catch { /* swallow */ }

// after
try {
  await submitSignature(req);
} catch (e) {
  showToast(e instanceof Error ? e.message : 'Signature failed');
  if (tokenExpired(e)) refreshParticipantLink();
}
Defensive patterns

Strategy: try-catch

Validate before calling

const req = request;
if (!req.participantToken) {
  setError('Participant token is required');
  return;
}
// ensure signature fields are populated before calling submitSignature

Type guard

export function isCompleteSignatureRequest(r: SignatureSubmissionRequest): boolean {
  return Boolean(r.participantToken);
}

Try / catch

try {
  await submitSignature(request);
} catch (e) {
  const msg = e instanceof Error ? e.message : 'Signature failed';
  showToast(msg);
  if (/token|expired|unauthorized/i.test(msg)) refreshParticipantLink();
}

Prevention

When it happens

Trigger: Backend rejects the signature (invalid signature image, missing required fields, participant token expired, session already completed/declined); network failure during the POST; participantToken missing so the session reload is skipped but the submit itself failed; concurrent double-submit where the second call hits a now-invalid state.

Common situations: Participant let their email token link expire; the workflow session was cancelled by an admin mid-sign; backend validation rejects an empty signature pad; flaky network on mobile; the request.participantToken is undefined so signature submits but state desyncs.

Related errors


AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13). Data as JSON: /api/errors/4e32245013fd1585. Report an issue: GitHub.