@@ -571,18 +571,23 @@ export default function ExamsPage() {
571571 headers : { "Content-Type" : "application/json" } ,
572572 body : JSON . stringify ( gradePayload ) ,
573573 } ) ;
574+ // 401 = session expired — stop retrying, prompt user
575+ if ( res . status === 401 ) {
576+ alert ( "Your session has expired. Please refresh the page and try again — your answer sheets were uploaded successfully." ) ;
577+ return ;
578+ }
574579 const json = await res . json ( ) ;
575580 if ( res . ok && json . data && json . data . run_id ) {
576581 setRunId ( json . data . run_id ) ;
577582 return ; // Success — stop retrying
578583 }
579- // If still parsing, retry after delay
584+ // If still parsing (400) , retry after delay
580585 const detail : string = json . detail || "" ;
581586 const stillParsing = detail . includes ( "still being parsed" ) || detail . includes ( "No parsed submissions" ) ;
582587 if ( stillParsing && attempt < MAX_RETRIES ) {
583588 setTimeout ( tryStartGrading , 10000 ) ; // retry in 10s
584- } else if ( ! stillParsing ) {
585- alert ( `Grading error : ${ detail } ` ) ;
589+ } else if ( ! stillParsing && detail ) {
590+ alert ( `Could not start grading : ${ detail } ` ) ;
586591 }
587592 // else exhausted retries silently — user can click "Start Grading Manually"
588593 } catch ( e : any ) {
@@ -612,8 +617,22 @@ export default function ExamsPage() {
612617 headers : { "Content-Type" : "application/json" } ,
613618 body : JSON . stringify ( gradePayload ) ,
614619 } ) ;
620+ if ( res . status === 401 ) {
621+ alert ( "Your session has expired. Please refresh the page and log back in to start grading." ) ;
622+ return ;
623+ }
615624 const json = await res . json ( ) ;
616- if ( ! res . ok ) throw new Error ( json . detail || "Grading failed to start. Submissions might still be parsing or rubric is not approved." ) ;
625+ if ( ! res . ok ) {
626+ const detail = json . detail || "" ;
627+ if ( detail . includes ( "still being parsed" ) ) {
628+ alert ( "Submissions are still being parsed. Please wait 1–2 minutes and try again." ) ;
629+ } else if ( detail . includes ( "No parsed submissions" ) ) {
630+ alert ( "No parsed submissions found yet. If you just uploaded files, wait 1–2 minutes for Celery to process them." ) ;
631+ } else {
632+ throw new Error ( detail || "Grading failed to start. Rubric may not be approved yet." ) ;
633+ }
634+ return ;
635+ }
617636 if ( json . data && json . data . run_id ) {
618637 setRunId ( json . data . run_id ) ;
619638 }
0 commit comments