GitHub Classroom: Students unable to access classroom-created repositories immediately after creation #171982
Replies: 30 comments 16 replies
-
Similar issue. I believe my classroom ID is 97207053. Link |
Beta Was this translation helpful? Give feedback.
-
I am having the same issue with one of my students in one of my classrooms. |
Beta Was this translation helpful? Give feedback.
-
I am having the same issue with one student in my classroom ID: 76087654 |
Beta Was this translation helpful? Give feedback.
-
Looks like a common issue - #72283 There's a script on that page that'll use |
Beta Was this translation helpful? Give feedback.
-
I've seen this a handful of times in the last 24 hours. I've just been deleting the repos to fix it, but it's a hassle. |
Beta Was this translation helpful? Give feedback.
-
This is a new issue I think.. I use classroom extensively and this is the first semester where this has been a problem. The issue seems to be that a student's invitation is immediately revoked and invalidated. I think this is a bug on github's end... Having said this, I do have a work around that is simpler than deletion but it's still a hassle Go to the student's repo |
Beta Was this translation helpful? Give feedback.
-
I am also having this issue with numerous students. |
Beta Was this translation helpful? Give feedback.
-
I've also seen this issue - from playing around with the invite link, I've found that I can trigger it about 70% of the time if I wait for more than 15 seconds after following the invite link to click 'Accept Assignment'. I've been encouraging my students to click all the way through promptly, which has helped reduce the number that need a manual fix-up - I suspect students with slow internet connections may be switching tabs while they wait for the link to load, leading to slow click-through rates. |
Beta Was this translation helpful? Give feedback.
-
I have the same issue in 4 assignments. There are more than 200 repositories created by students and about 20 of them have this problem. I have tried three different ways so far.
All methods have the chance to work or not work. What I can do is just let student roll the dice and hope it will work well. I still have unlucky students who fails with all the three ways. I hope the team will fix this problem soon. |
Beta Was this translation helpful? Give feedback.
-
Unfortunately, I am experiencing this issue this year too. I have used Github Classroom for several years and not experienced this before. Out of my 150 students about 15-20% are experiencing the problem. I stumbled upon the manual fix of uninviting them and reinviting myself. I will try out the script above, if this occurs on the next assignment. I do wonder if the root problem of github not thinking the student is part of the enterprise organization is due to me forking my base projects from my source organization. Up until late last year I used to import the repositories from my source organization into this year's organization, but that stopped working late in the school year last year. |
Beta Was this translation helpful? Give feedback.
-
Hi everyone 👋, As many of you have likely experienced, there’s an issue across GitHub Classroom causing GitHub Classroom invitations to expire before students can accept them 😕. While we all hope GitHub resolves this soon, I built a temporary workaround that has already helped our students regain access quickly. 🔗 Example of the Hosted Tool: https://github-reinvite.vercel.app/ How it works Students who lost access to a Classroom-generated repository can: For faculty, you'll need to host this application yourself using Vercel or anything you'd like: Fork the repo and run it on your own infrastructure 🌐 This is a community tool built in one night to help educators and students while we wait for a permanent fix from GitHub ❤️. ☕ If this helped you or your students, consider supporting the project: Buy me a coffee Let’s keep our students coding without roadblocks! 💻✨ |
Beta Was this translation helpful? Give feedback.
-
The workaround is tedious but effective: I have to manually delete the affected repos and re-create them—sometimes more than once. Unfortunately, the most frustrating part is that I have to re-enter each repo name by hand. Please fix it asap! Thank you MS. |
Beta Was this translation helpful? Give feedback.
-
This problem is pernicious; I long for the days of yore when GitHub actually provided SOME kind of support for GitHub Classroom (although it has always been mediocre to poor). I am currently using this script to fix the failed invitations, you are welcome to it if it works for you. Set the ORG variable at the top to your GitHub classroom organization, and run it as:
For example, if you have configured GitHub Classroom to create repositories named If it breaks, you can have the broken parts for free. But unlike GitHub and GitHub Classroom, you also get the source, so you can fix it! #!/bin/sh
GH=gh
ORG=
if ! jq -n . > /dev/null 2>&1; then
echo "jq does not seem to be installed, cannot continue" 1>&2
exit 1
fi
if ! gh help > /dev/null 2>&1; then
echo "gh does not seem to be installed, cannot continue" 1>&2
exit 1
fi
if ! gh auth status -a > /dev/null 2>&1; then
echo "gh does not seem to be authenticated, please run \`gh auth\` and try again"
exit 1
fi
if [ $# -ne 2 ]; then
echo "usage: $0 <assignment prefix> <ubitname>" 1>&2
exit 1
fi
PREFIX="$1"
GHUSER="$2"
GHREPO="$ORG/$PREFIX-$GHUSER"
checkexists() {
$GH repo view "$1" > /dev/null 2>&1
}
if ! checkexists "$GHREPO"; then
echo "error: Repository $GHREPO does not seem to be usable" 1>&2
exit 1
fi
echo "Removing $GHUSER from $GHREPO"
echo "Checking for invitation first"
ID=`$GH api -XGET repos/$GHREPO/invitations | jq '.[] | select(.invitee.login == "'"$GHUSER"'").id'`
if [ "x$ID" != "x" ]; then
if $GH api --silent -XDELETE "repos/$GHREPO/invitations/$ID"; then
echo "Invitation deleted, moving on"
else
echo "Failed to delete invitation, aborting" 1>&2
exit 1
fi
else
echo "No invitation found, trying to remove user entirely"
if ! $GH api --silent -XDELETE "repos/$GHREPO/collaborators/$GHUSER"; then
echo "Failed to remove $GHUSER from repository" 1>&2
exit 1
fi
fi
echo "Adding $GHUSER to $GHREPO as writer"
if ! $GH api --silent -XPUT "repos/$GHREPO/collaborators/$GHUSER" -f permission=write; then
echo "Failed to add $GHUSER to repository" 1>&2
exit 1
fi
echo "Done!"
echo
echo "User can accept https://github.com/$GHREPO/invitations now" |
Beta Was this translation helpful? Give feedback.
-
+1 for this problem. And some of these are for in-class assignments making the shell script workaround a less-than desirable option. Seems like something GitHub could fix? |
Beta Was this translation helpful? Give feedback.
-
Happening for me too. Deleting the repo didn't work for my student, but re-inviting them did. Hoping this gets fixed soon, because I have daily assignments and realistically can't keep using a workaround. |
Beta Was this translation helpful? Give feedback.
-
This is happening to me too — it seems to be a trending issue. The resolution I’ve found is to access each student’s repo, cancel the invite in the repo settings, and then re-invite them. The student then accepts the invitation from their GitHub inbox. However, doing this for every single assignment is cumbersome. Interestingly, after accepting the re-invite, the student is added as an outside collaborator, but they still cannot access new assignments, and the process has to be repeated. |
Beta Was this translation helpful? Give feedback.
-
I've used GitHub Classroom for years and this is happening for the first time ever. Thank you for all the workaround suggestions! Hopefully GitHub will fix it fairly soon because it is very frustrating and confusing for beginning students. |
Beta Was this translation helpful? Give feedback.
-
I have 28 students in my class, and I have had 5 students facing this issue during the past 2 weeks, for two assignments.
|
Beta Was this translation helpful? Give feedback.
-
Student invitations keep getting revoked and invalidated, which seems like a bug on GitHub’s end. Students get added to the repo as admins after accepting the assignment but then they keep getting "The invitation is invalid". The only fix is to delete their usernames from the repo and add them again manually, which is frustrating. This is related to https://github.com/orgs/community/discussions/72283 |
Beta Was this translation helpful? Give feedback.
-
Got the same. It's annoying :-/ |
Beta Was this translation helpful? Give feedback.
-
Having the same issue here. Ironically worked flawlessly for me when testing, but the first 2 students that accepted the assignment got the bug, so I had to drop using it. Really hope they fix this soon. |
Beta Was this translation helpful? Give feedback.
-
This is really annoying problem and re-invite students seems the only solution so far. I first thought it is a sort of throughput issue, so spread acceptance of an assignment may mitigate the issue, but it didn't. Shouldn't it be handled as a higher priority issue? |
Beta Was this translation helpful? Give feedback.
-
Same issue here, been using Github classroom for years. Really unfortunate issue. |
Beta Was this translation helpful? Give feedback.
-
Me and my colleagues are also having this issue. |
Beta Was this translation helpful? Give feedback.
-
@eblanton thanks so much for your script, I haven't tested this yet, but I wanted to mention in this thread that we are seeing some students with this issue show up on the repo as READ instead of as a pending invitation. So it seems like this issue occurs only intermittently and then usually will be a pending invite but a small percentage of those students could be on the repo as READ instead of WRITE (but they still see the same repository access issue web page when trying to get to the repo) |
Beta Was this translation helpful? Give feedback.
-
I observed this bug when inviting people to repositories using a GitHub bot (not via Classroom, a different bot). Worked perfectly in July and August, stopped working about 3-4 days ago. So my guess is that this is NOT a Classroom problem, but a bot / REST API issue. |
Beta Was this translation helpful? Give feedback.
-
Did anyone file a ticket about this? |
Beta Was this translation helpful? Give feedback.
-
Same issue here. This is becoming a really big problem for me. It started out as a few students having the problem. Now, most of the students are having the problem. I have about 30 students with multiple assignments every week. I can't fix the problem until a student encounters it. The number of clicks per fix is significant, and students get blocked when they try to access a new assignment outside of class. This is causing lot of wasted time for me and my students. Github, you are creating a ton of negative advertisement to these young potential future customers as I explain to them over and over again that Github has a major bug and isn't communicating about it and is very slow to fix it. |
Beta Was this translation helpful? Give feedback.
-
I am also have the same problem. It happened to about 5-6 students on my first assignment about 1.5 weeks ago. Now for the second assignment, 20+ students have had this problem (out of 50+ students). This is becoming quite annoying to say the least. |
Beta Was this translation helpful? Give feedback.
-
Following on eblanton initial script, I added a few more features to do --batch mode and a --list (discover) and --dry-run (mock run). I test the script in two of my assignments, and it works: #!/usr/bin/env bash
GH=gh
if ! jq -n . > /dev/null 2>&1; then
echo "jq does not seem to be installed, cannot continue" 1>&2
exit 1
fi
if ! gh help > /dev/null 2>&1; then
echo "gh does not seem to be installed, cannot continue" 1>&2
exit 1
fi
if ! gh auth status -a > /dev/null 2>&1; then
echo "gh does not seem to be authenticated, please run \`gh auth\` and try again"
exit 1
fi
# Parse command line options
DRY_RUN=false
LIST_MODE=false
VERBOSE=false
BATCH_MODE=false
BATCH_FILE=""
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run|-n)
DRY_RUN=true
shift
;;
--list|-l)
LIST_MODE=true
shift
;;
--verbose|-v)
VERBOSE=true
shift
;;
--batch|-b)
BATCH_MODE=true
BATCH_FILE="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS] <assignment prefix> <ubitname|batch-file> <organization>"
echo "Options:"
echo " --dry-run, -n Show what would be done without making changes"
echo " --list, -l List repository status without making changes"
echo " --verbose, -v Show detailed output"
echo " --batch, -b <file> Process multiple users from a file (one username per line)"
echo " --help, -h Show this help message"
echo ""
echo "Single user examples:"
echo " $0 homework1 student-username org-name"
echo " $0 --dry-run assignment2 student-github-user organization"
echo " $0 --list project1 github-username org-name"
echo ""
echo "Batch mode examples:"
echo " $0 --batch students.txt homework1 organization"
echo " $0 --list --batch userlist.txt assignment2 org-name"
echo " $0 --dry-run --batch class-roster.txt project1 organization"
echo ""
echo "Batch file format (one username per line):"
echo " student1-github"
echo " student2-username"
echo " student3-user"
exit 0
;;
-*)
echo "Unknown option: $1" 1>&2
echo "Use --help for usage information" 1>&2
exit 1
;;
*)
break
;;
esac
done
# Validate arguments based on mode
if [ "$BATCH_MODE" = true ]; then
if [ $# -ne 2 ]; then
echo "usage: $0 [OPTIONS] --batch <batch-file> <assignment prefix> <organization>" 1>&2
echo "Use --help for more information" 1>&2
exit 1
fi
if [ ! -f "$BATCH_FILE" ]; then
echo "error: Batch file '$BATCH_FILE' does not exist" 1>&2
exit 1
fi
PREFIX="$1"
ORG="$2"
GHUSER="" # Not used in batch mode
else
if [ $# -ne 3 ]; then
echo "usage: $0 [OPTIONS] <assignment prefix> <ubitname> <organization>" 1>&2
echo "Use --help for more information" 1>&2
exit 1
fi
PREFIX="$1"
GHUSER="$2"
ORG="$3"
fi
check_repo_detailed() {
local repo="$1"
echo "Checking repository accessibility..."
if $GH repo view "$repo" > /dev/null 2>&1; then
echo "✓ Repository exists and is accessible"
# Quick content check
if $GH api "repos/$repo/contents" > /dev/null 2>&1; then
echo "✓ Repository has content"
else
echo "⚠ Repository appears to be empty"
fi
return 0
else
echo "✗ Repository check failed"
return 1
fi
}
suggest_alternatives() {
local org="$1"
local prefix="$2"
local user="$3"
echo "Searching for similar repositories in organization '$org'..."
# Try different variations of the repository name
local variations=(
"$org/$prefix$user"
"$org/$user-$prefix"
"$org/$prefix\_$user"
"$org/$user\_$prefix"
"$org/$user"
"$org/${prefix,,}-$user" # lowercase prefix
"$org/$prefix-${user,,}" # lowercase user
)
local found_repos=()
for variation in "${variations[@]}"; do
if $GH repo view "$variation" > /dev/null 2>&1; then
found_repos+=("$variation")
fi
done
if [ ${#found_repos[@]} -gt 0 ]; then
echo "Found similar repositories:"
for repo in "${found_repos[@]}"; do
echo " - https://github.com/$repo"
done
else
# Search for repositories containing parts of the expected name
echo "Searching for repositories with similar names..."
local search_results=$($GH search repos --owner="$org" "$prefix" --limit 10 2>/dev/null | grep "^$org/" || true)
if [ -n "$search_results" ]; then
echo "Repositories in '$org' containing '$prefix':"
echo "$search_results" | sed 's/^/ - https:\/\/github.com\//'
else
echo "No repositories found in '$org' containing '$prefix'"
fi
fi
}
# Function to process a single user
process_single_user() {
local prefix="$1"
local user="$2"
local org="$3"
local repo="$org/$prefix-$user"
echo "=== Processing User: $user ==="
echo "Repository: $repo"
echo "Assignment: $prefix"
echo "Organization: $org"
echo
# Check if repository exists
if ! check_repo_detailed "$repo"; then
echo
suggest_alternatives "$org" "$prefix" "$user"
echo "❌ SKIPPING: Repository $repo does not exist or is not accessible"
echo
return 1
fi
echo
local repo_corrupted=false
if ! check_permissions "$repo" "$user"; then
repo_corrupted=true
fi
echo
check_invitations "$repo" "$user"
echo
# Determine repository status
if [ "$repo_corrupted" = true ]; then
echo "🚨 REPOSITORY CORRUPTION DETECTED!"
echo " Student '$user' should be a collaborator but is not."
echo " This indicates the repository access is corrupted and needs to be fixed."
echo
else
echo "✅ Repository access appears normal."
echo " Student '$user' is properly configured as a collaborator."
echo
fi
# If in list mode, just show status
if [ "$LIST_MODE" = true ]; then
if [ "$repo_corrupted" = true ]; then
echo "❌ Repository: $repo - CORRUPTED (student not a collaborator)"
else
echo "✅ Repository: $repo - OK (student is a collaborator)"
fi
echo
return 0
fi
# Process the fix
if [ "$repo_corrupted" = true ]; then
echo "=== Fixing Repository Corruption ==="
echo "Removing any existing access and re-inviting $user..."
else
echo "=== Re-cycling Collaborator Access ==="
echo "Removing and re-adding $user to refresh permissions..."
fi
if [ "$DRY_RUN" = true ]; then
if [ "$repo_corrupted" = true ]; then
echo "[DRY RUN] Would fix corruption by removing $user from $repo"
else
echo "[DRY RUN] Would re-cycle permissions for $user from $repo"
fi
echo "[DRY RUN] Would check for invitation first..."
else
echo "Checking for invitation first..."
fi
# Get and process invitations
local id=$(gh api -XGET "repos/$repo/invitations" | jq '.[] | select(.invitee.login == "'"$user"'").id' 2>/dev/null || echo "")
if [ "x$id" != "x" ]; then
echo "Found pending invitation (ID: $id)"
if [ "$DRY_RUN" != true ]; then
if gh api --silent -XDELETE "repos/$repo/invitations/$id"; then
echo "✓ Invitation deleted successfully"
else
echo "✗ Failed to delete invitation" 1>&2
echo "Try manually checking: https://github.com/$repo/settings/access" 1>&2
return 1
fi
else
echo "[DRY RUN] Would delete invitation"
fi
else
echo "No pending invitation found"
echo "Checking if user is already a collaborator..."
if gh api "repos/$repo/collaborators/$user" > /dev/null 2>&1; then
echo "User is currently a collaborator, removing..."
if [ "$DRY_RUN" != true ]; then
if gh api --silent -XDELETE "repos/$repo/collaborators/$user"; then
echo "✓ User removed successfully"
else
echo "✗ Failed to remove $user from repository" 1>&2
echo "You may need to remove them manually from: https://github.com/$repo/settings/access" 1>&2
return 1
fi
else
echo "[DRY RUN] Would remove user"
fi
else
echo "User is not currently a collaborator"
fi
fi
echo
echo "Adding $user to $repo as writer..."
if [ "$DRY_RUN" != true ]; then
if ! gh api --silent -XPUT "repos/$repo/collaborators/$user" -f permission=write; then
echo "✗ Failed to add $user to repository" 1>&2
echo "Possible reasons:" 1>&2
echo " - User '$user' does not exist on GitHub" 1>&2
echo " - You don't have admin access to the repository" 1>&2
echo " - Organization policies prevent adding collaborators" 1>&2
echo " - Rate limiting or API issues" 1>&2
echo "Try adding manually: https://github.com/$repo/settings/access" 1>&2
return 1
fi
echo "✓ User added successfully!"
else
echo "[DRY RUN] Would add user as writer"
fi
echo
echo "=== Summary ==="
echo "Repository: $repo"
echo "Student: $user"
echo "Permission: write"
if [ "$repo_corrupted" = true ]; then
echo "Status: ✅ CORRUPTION FIXED - Repository access has been restored"
else
echo "Status: ✅ PERMISSIONS REFRESHED - Repository access has been re-cycled"
fi
echo
if [ "$DRY_RUN" != true ]; then
echo "Next steps:"
echo "1. User can accept the invitation at: https://github.com/$repo/invitations"
echo "2. Or check all invitations at: https://github.com/notifications"
echo "3. Repository access can be managed at: https://github.com/$repo/settings/access"
fi
echo
return 0
}
# Function to process batch mode
process_batch() {
local batch_file="$1"
local prefix="$2"
local org="$3"
echo "=== BATCH MODE ==="
echo "Batch file: $batch_file"
echo "Assignment: $prefix"
echo "Organization: $org"
echo
# Read and validate batch file
if [ ! -r "$batch_file" ]; then
echo "error: Cannot read batch file '$batch_file'" 1>&2
exit 1
fi
local users=()
while IFS= read -r line; do
# Skip empty lines and comments
if [[ -n "$line" && ! "$line" =~ ^[[:space:]]*# ]]; then
# Trim whitespace
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ -n "$line" ]]; then
users+=("$line")
fi
fi
done < "$batch_file"
if [ ${#users[@]} -eq 0 ]; then
echo "error: No valid usernames found in batch file '$batch_file'" 1>&2
exit 1
fi
echo "Found ${#users[@]} users to process:"
for user in "${users[@]}"; do
echo " - $user"
done
echo
# Process each user
local success_count=0
local failure_count=0
local corrupted_count=0
local ok_count=0
for user in "${users[@]}"; do
echo "────────────────────────────────────────────────────────────────"
if process_single_user "$prefix" "$user" "$org"; then
((success_count++))
# Check if it was corrupted by looking at the output
if check_permissions "$org/$prefix-$user" "$user" > /dev/null 2>&1; then
((ok_count++))
else
((corrupted_count++))
fi
else
((failure_count++))
fi
echo
done
echo "════════════════════════════════════════════════════════════════"
echo "=== BATCH PROCESSING SUMMARY ==="
echo "Total users processed: ${#users[@]}"
echo "Successful operations: $success_count"
echo "Failed operations: $failure_count"
if [ "$LIST_MODE" = true ]; then
echo "Repositories OK: $ok_count"
echo "Repositories CORRUPTED: $corrupted_count"
else
echo "Repositories fixed/processed: $success_count"
fi
echo
if [ $failure_count -gt 0 ]; then
echo "⚠ Some operations failed. Check the output above for details."
exit 1
else
echo "✅ All operations completed successfully!"
fi
}
check_permissions() {
local repo="$1"
local user="$2"
echo "Checking user permissions..."
# Check if user is a collaborator
if $GH api "repos/$repo/collaborators/$user" > /dev/null 2>&1; then
echo "✓ $user is a collaborator"
return 0
else
echo "⚠ $user is not currently a collaborator - REPOSITORY IS CORRUPTED"
return 1
fi
}
check_invitations() {
local repo="$1"
local user="$2"
echo "Checking pending invitations..."
local temp_file=$(mktemp)
if $GH api "repos/$repo/invitations" > "$temp_file" 2>/dev/null; then
local invitations=$(jq --arg user "$user" '.[] | select(.invitee.login == $user)' "$temp_file" 2>/dev/null || echo "")
if [ -n "$invitations" ]; then
local invitation_id=$(echo "$invitations" | jq -r '.id' 2>/dev/null || echo "unknown")
local created_at=$(echo "$invitations" | jq -r '.created_at' 2>/dev/null || echo "unknown")
echo "ℹ Found pending invitation (ID: $invitation_id, created: $created_at)"
rm -f "$temp_file"
return 0
fi
fi
rm -f "$temp_file"
echo "ℹ No pending invitations found for $user"
return 1
}
# Main execution logic
if [ "$BATCH_MODE" = true ]; then
# Batch mode: process multiple users from file
process_batch "$BATCH_FILE" "$PREFIX" "$ORG"
else
# Single mode: process one user
process_single_user "$PREFIX" "$GHUSER" "$ORG"
fi I hope it helps some of you. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
Students in my class are accepting assignments and a good portion of them are being told that they cannot access the repository.
When I go to their repository settings and check their access , their user is "pending invite", but none of them can accept the invite.
Only removing their access, and then re-inviting them manually myself, solves the problem (they can then accept the invite).
This isn't a user error or something on my part as far as I can tell. I've run three successful assignments already over the past couple of weeks and this has the same setup.
For reference, my classroom ID is 845574
Beta Was this translation helpful? Give feedback.
All reactions