diff --git a/models/repo/repo.go b/models/repo/repo.go
index 7cbd5867b7..00e875407c 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -149,8 +149,8 @@ type Repository struct {
 	IsEmpty    bool `xorm:"INDEX"`
 	IsArchived bool `xorm:"INDEX"`
 	IsMirror   bool `xorm:"INDEX"`
-	*Mirror    `xorm:"-"`
-	Status     RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
+
+	Status RepositoryStatus `xorm:"NOT NULL DEFAULT 0"`
 
 	RenderingMetas         map[string]string `xorm:"-"`
 	DocumentRenderingMetas map[string]string `xorm:"-"`
diff --git a/modules/context/repo.go b/modules/context/repo.go
index b20ea26e4e..5e90e8aec0 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -61,7 +61,6 @@ type Repository struct {
 	RepoLink     string
 	CloneLink    repo_model.CloneLink
 	CommitsCount int64
-	Mirror       *repo_model.Mirror
 
 	PullRequest *PullRequest
 }
@@ -380,13 +379,9 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
 	ctx.Data["Permission"] = &ctx.Repo.Permission
 
 	if repo.IsMirror {
-		ctx.Repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID)
+		pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
 		if err == nil {
-			ctx.Repo.Mirror.Repo = repo
-			ctx.Data["IsPullMirror"] = true
-			ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune
-			ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval
-			ctx.Data["Mirror"] = ctx.Repo.Mirror
+			ctx.Data["PullMirror"] = pullMirror
 		} else if err != repo_model.ErrMirrorNotExist {
 			ctx.ServerError("GetMirrorByRepoID", err)
 			return
diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go
index 16b718c919..578b70194e 100644
--- a/routers/web/repo/setting.go
+++ b/routers/web/repo/setting.go
@@ -198,6 +198,15 @@ func SettingsPost(ctx *context.Context) {
 			return
 		}
 
+		pullMirror, err := repo_model.GetMirrorByRepoID(ctx, ctx.Repo.Repository.ID)
+		if err == repo_model.ErrMirrorNotExist {
+			ctx.NotFound("", nil)
+			return
+		}
+		if err != nil {
+			ctx.ServerError("GetMirrorByRepoID", err)
+			return
+		}
 		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 		// as an error on the UI for this action
 		ctx.Data["Err_RepoName"] = nil
@@ -209,15 +218,15 @@ func SettingsPost(ctx *context.Context) {
 			return
 		}
 
-		ctx.Repo.Mirror.EnablePrune = form.EnablePrune
-		ctx.Repo.Mirror.Interval = interval
-		ctx.Repo.Mirror.ScheduleNextUpdate()
-		if err := repo_model.UpdateMirror(ctx, ctx.Repo.Mirror); err != nil {
+		pullMirror.EnablePrune = form.EnablePrune
+		pullMirror.Interval = interval
+		pullMirror.ScheduleNextUpdate()
+		if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
 			ctx.ServerError("UpdateMirror", err)
 			return
 		}
 
-		u, err := git.GetRemoteURL(ctx, ctx.Repo.Repository.RepoPath(), ctx.Repo.Mirror.GetRemoteName())
+		u, err := git.GetRemoteURL(ctx, ctx.Repo.Repository.RepoPath(), pullMirror.GetRemoteName())
 		if err != nil {
 			ctx.Data["Err_MirrorAddress"] = true
 			handleSettingRemoteAddrError(ctx, err, form)
@@ -237,7 +246,7 @@ func SettingsPost(ctx *context.Context) {
 			return
 		}
 
-		if err := mirror_service.UpdateAddress(ctx, ctx.Repo.Mirror, address); err != nil {
+		if err := mirror_service.UpdateAddress(ctx, pullMirror, address); err != nil {
 			ctx.ServerError("UpdateAddress", err)
 			return
 		}
@@ -259,9 +268,9 @@ func SettingsPost(ctx *context.Context) {
 			}
 		}
 
-		ctx.Repo.Mirror.LFS = form.LFS
-		ctx.Repo.Mirror.LFSEndpoint = form.LFSEndpoint
-		if err := repo_model.UpdateMirror(ctx, ctx.Repo.Mirror); err != nil {
+		pullMirror.LFS = form.LFS
+		pullMirror.LFSEndpoint = form.LFSEndpoint
+		if err := repo_model.UpdateMirror(ctx, pullMirror); err != nil {
 			ctx.ServerError("UpdateMirror", err)
 			return
 		}
diff --git a/services/convert/repository.go b/services/convert/repository.go
index f470fd1656..54a61efe43 100644
--- a/services/convert/repository.go
+++ b/services/convert/repository.go
@@ -124,11 +124,10 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.Acc
 	mirrorInterval := ""
 	var mirrorUpdated time.Time
 	if repo.IsMirror {
-		var err error
-		repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID)
+		pullMirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID)
 		if err == nil {
-			mirrorInterval = repo.Mirror.Interval.String()
-			mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime()
+			mirrorInterval = pullMirror.Interval.String()
+			mirrorUpdated = pullMirror.UpdatedUnix.AsTime()
 		}
 	}
 
diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl
index 03f5a2e78f..33791fd512 100644
--- a/templates/repo/header.tmpl
+++ b/templates/repo/header.tmpl
@@ -39,8 +39,8 @@
 						<a class="rss-icon gt-ml-3" href="{{$.RepoLink}}.rss" data-tooltip-content="{{$.locale.Tr "rss_feed"}}">{{svg "octicon-rss" 18}}</a>
 					{{end}}
 				</div>
-				{{if $.IsPullMirror}}
-					{{$address := MirrorRemoteAddress $.Context . $.Mirror.GetRemoteName false}}
+				{{if $.PullMirror}}
+					{{$address := MirrorRemoteAddress $.Context . $.PullMirror.GetRemoteName false}}
 					<div class="fork-flag">{{$.locale.Tr "repo.mirror_from"}} <a target="_blank" rel="noopener noreferrer" href="{{$address.Address}}">{{$address.Address}}</a></div>
 				{{end}}
 				{{if .IsFork}}<div class="fork-flag">{{$.locale.Tr "repo.forked_from"}} <a href="{{.BaseRepo.Link}}">{{.BaseRepo.FullName}}</a></div>{{end}}
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index b26656bf28..efcdaceb37 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -84,12 +84,21 @@
 						</tr>
 					</thead>
 					{{end}}
-					{{if .Repository.IsMirror}}
+					{{if and .Repository.IsMirror (not .PullMirror)}}
+						{{/* even if a repo is a pull mirror (IsMirror=true), the PullMirror might still be nil if the mirror migration is broken */}}
+						<tbody>
+							<tr>
+								<td colspan="4">
+									<span class="text red gt-db gt-py-4 gt-border-secondary-bottom">{{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}}: {{$.locale.Tr "error.occurred"}}</span>
+								</td>
+							</tr>
+						</tbody>
+					{{else if .PullMirror}}
 					<tbody>
 						<tr>
-							<td>{{(MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName false).Address}}</td>
+							<td>{{(MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false).Address}}</td>
 							<td>{{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}}</td>
-							<td>{{DateTime "full" .Mirror.UpdatedUnix}}</td>
+							<td>{{DateTime "full" .PullMirror.UpdatedUnix}}</td>
 							<td class="right aligned">
 								<form method="post" class="gt-dib">
 									{{.CsrfTokenHtml}}
@@ -107,15 +116,15 @@
 									<div class="inline field {{if .Err_EnablePrune}}error{{end}}">
 										<label>{{.locale.Tr "repo.mirror_prune"}}</label>
 										<div class="ui checkbox">
-									<input id="enable_prune" name="enable_prune" type="checkbox" {{if .MirrorEnablePrune}}checked{{end}}>
+									<input id="enable_prune" name="enable_prune" type="checkbox" {{if .PullMirror.EnablePrune}}checked{{end}}>
 									<label>{{.locale.Tr "repo.mirror_prune_desc"}}</label>
 										</div>
 									</div>
 									<div class="inline field {{if .Err_Interval}}error{{end}}">
 										<label for="interval">{{.locale.Tr "repo.mirror_interval" .MinimumMirrorInterval}}</label>
-										<input id="interval" name="interval" value="{{.MirrorInterval}}">
+										<input id="interval" name="interval" value="{{.PullMirror.Interval}}">
 									</div>
-									{{$address := MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName false}}
+									{{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}}
 									<div class="field {{if .Err_MirrorAddress}}error{{end}}">
 										<label for="mirror_address">{{.locale.Tr "repo.mirror_address"}}</label>
 										<input id="mirror_address" name="mirror_address" value="{{$address.Address}}" required>
@@ -142,13 +151,13 @@
 									<div class="inline field">
 										<label>{{.locale.Tr "repo.mirror_lfs"}}</label>
 										<div class="ui checkbox">
-											<input id="mirror_lfs" name="mirror_lfs" type="checkbox" {{if .Mirror.LFS}}checked{{end}}>
+											<input id="mirror_lfs" name="mirror_lfs" type="checkbox" {{if .PullMirror.LFS}}checked{{end}}>
 											<label>{{.locale.Tr "repo.mirror_lfs_desc"}}</label>
 										</div>
 									</div>
 									<div class="field {{if .Err_LFSEndpoint}}error{{end}}">
 										<label for="mirror_lfs_endpoint">{{.locale.Tr "repo.mirror_lfs_endpoint"}}</label>
-										<input id="mirror_lfs_endpoint" name="mirror_lfs_endpoint" value="{{.Mirror.LFSEndpoint}}" placeholder="{{.locale.Tr "repo.migrate_options_lfs_endpoint.placeholder"}}">
+										<input id="mirror_lfs_endpoint" name="mirror_lfs_endpoint" value="{{.PullMirror.LFSEndpoint}}" placeholder="{{.locale.Tr "repo.migrate_options_lfs_endpoint.placeholder"}}">
 										<p class="help">{{.locale.Tr "repo.mirror_lfs_endpoint_desc" "https://github.com/git-lfs/git-lfs/blob/main/docs/api/server-discovery.md#server-discovery" | Str2html}}</p>
 									</div>
 									{{end}}
@@ -160,7 +169,7 @@
 						</tr>
 					</tbody>
 					<thead><tr><th colspan="4"></th></tr></thead>
-					{{end}}
+					{{end}}{{/* end if: IsMirror */}}
 					<tbody>
 						{{range .PushMirrors}}
 						<tr>