11 Help

Troubleshooting.

Most surprises in Studio fall into one of these patterns. Skim once; come back as a reference when something’s off.
01 Auth + roles

“I changed a user’s role but it doesn’t take effect.”

Auth.js stores the user’s role in a session JWT, not a database lookup on every request. When an admin changes a role from user to teacher on the Users tab, the database updates immediately — but any existing session for that user still carries the old role until the JWT is reissued at next sign-in.

Fix: tell the user to sign out, then sign back in. The new role applies on the new session. There’s no “invalidate session” button; we deliberately don’t kick people out of the studio when admin metadata changes.

Test: as the admin, switch the role and refresh the Users tab. The dropdown reflects the new value (DB is updated). As the user, sign out → sign in. Their dashboard now shows surfaces matching the new role (graduation cap for teachers, shield for admins).

02 Scrolling

“The page won’t scroll past the viewport.”

Studio sets body { overflow: hidden } globally for the chat-and-canvas layout. Pages that need to scroll (admin, teacher dashboard, courses list, commons) are individually responsible for their own scroll container.

If you find a page where you can’t scroll past content that runs below the viewport, that page is missing the inline scroll fix. Tell us — file an issue with the URL and a short description, and we’ll patch it. The fix pattern is documented in commit history.

Workaround: open browser devtools, find the page’s outer wrapper, manually set height: 100vh and add overflow-y: auto to its inner content area. Won’t persist; only useful to confirm the page is the issue.

03 Cohort UI

“The cohort panel says no cohort attached.”

You’re looking at a course created before the 1:1 cohort model shipped. The first time you open the cohort panel for any course, the studio auto-creates a cohort row pinned to that course. If you’re seeing the “no cohort” banner today, just open the cohort panel once — the row gets created lazily, and the banner is replaced with the empty roster + working buttons.

If the banner keeps reappearing after multiple loads, file an issue. Don’t edit the database manually.

04 CSV imports

“The preview shows 0 valid emails.”

Two causes:

  • The email column is missing. Open the file in a spreadsheet and confirm there’s a column with values like name@domain.tld. Re-export from your registrar with email included.
  • The values aren’t real emails. Some exports list student IDs as 123456@school.edu internally but render them as 123456 with the domain implicit. The parser only accepts fully-qualified addresses. Re-export with explicit @domain.

If you see “Skipped (no email)” with a non-zero count, those rows had something in the email column but it wasn’t a valid address. The parser drops them silently and continues with the rest. Open the file and check those rows manually.

05 Send invites

“The Send invites button is disabled.”

The button is disabled when there are zero pending students. Reasons:

  • You haven’t added anyone to the cohort yet — only enrolled members appear, and enrolled members already have accounts so they don’t need invites.
  • You added students by single-email and they all already had Studio accounts. They went straight to enrolled, not pending.
  • Everyone you invited has already signed in — they’ve been promoted from pending to enrolled.

To check: the cohort header subtitle reads “X enrolled · Y pending sign-up.” If Y is zero, the button is correctly disabled — there’s nobody to invite.

06 Send invites

“Sent 0, skipped N (sent <60s ago).”

You clicked Send invites twice within a minute. The studio applies a 60-second per-recipient cooldown to prevent accidental spam. Wait the full minute, click again. The skipped students get sent on the second click.

The cooldown is per-recipient, so if you mix-and-match (some students were sent 30 seconds ago, others a week ago), the green “sent” count and yellow “skipped” count add up to your total pending — only the ones too-recently-invited are skipped.

07 Send invites

“Email invites are not configured.”

Server-side SMTP credentials aren’t set. Contact your admin. The studio expects four environment variables (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS) plus a from-address (AUTH_EMAIL_FROM or SMTP_FROM). Until those are set, the invite endpoint returns HTTP 503 and the UI surfaces this error.

08 Lessons

“The student switched to image mode but the lesson is locked to code.”

That can’t actually happen. The studio enforces media-type locks server-side — the chat API rejects (HTTP 409 lesson_media_locked) any request whose mode isn’t in the lesson’s allowed set. The UI also hides disallowed mode tabs.

If a student tells you they switched modes, one of three things is true:

  • The lesson’s media-types field is empty (= unrestricted). Go to the lesson editor and set chips.
  • They’re looking at a different lesson than you think.
  • They started the session before you set the chips. Existing sessions keep their old context. New sessions will respect the new chips.
09 Lessons

“I can’t delete a lesson — it says X student sessions exist.”

Working as designed. The studio refuses to delete a lesson that students have ever worked on, because deletion would cascade-remove their session history, scores, and submitted work. Edit the lesson in place instead, or archive the entire course at the end of the term.

If you genuinely need to remove a lesson with student work, the only path is to either delete the entire course (cascades through everything) or to ask a developer to manually clean up the database. There’s no UI for the latter.

10 Cloning

“I cloned a course and the cohort is empty.”

That’s correct. Cloning a course copies the lessons but creates a fresh empty cohort on the clone. Cohorts are per-course (1:1 with the course); copying memberships across would require deciding what to do with each student, which has no obvious right answer (the same student in two sections? in just one?). The studio punts: empty cohort, you decide.

To re-roster the clone: import the same CSV you used originally, or copy individual emails by hand from the original cohort.

11 Filing issues

When in doubt, open one.

If you hit something not covered here, the project tracks issues at irajgreenberg/ij8/issues. Filing is encouraged — even minor wording suggestions help. The Studio also has an in-app feedback widget (the corner button) that drops a pre-filled issue with your viewport context attached.