diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 16353474af6548f52b62ee3870eab0eb704a7d95..51832014f532b41534c0918285f8fb4c43f6a73f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -10,8 +10,19 @@ jobs:
       - uses: actions/setup-go@v4
         with:
           go-version: '1.20'
-      - run: './build.sh' # verify the thing compiles first
+      - run: './build.sh' # verify the thing compiles
+  static:
+    name: 'Go Static (1.20)'
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - uses: actions/setup-go@v4
+        with:
+          go-version: '1.20'
       - run: 'go vet ./...'
+      - run: 'go install honnef.co/go/tools/cmd/staticcheck@latest'
+        name: "Install staticcheck"
+      - run: 'staticcheck ./...'
   test:
     name: 'Go Test (1.20)'
     runs-on: ubuntu-latest
diff --git a/api/_routers/01-install_metadata.go b/api/_routers/01-install_metadata.go
index 8a9102e8c8de083eb1e52b28462a943ed5e05687..22c41023f886c36147a6b1edc3cbf41e346aca7c 100644
--- a/api/_routers/01-install_metadata.go
+++ b/api/_routers/01-install_metadata.go
@@ -6,14 +6,10 @@ import (
 	"strconv"
 
 	"github.com/sirupsen/logrus"
+	"github.com/turt2live/matrix-media-repo/common"
 	"github.com/turt2live/matrix-media-repo/util"
 )
 
-const requestIdCtxKey = "mmr.request_id"
-const actionNameCtxKey = "mmr.action"
-const shouldIgnoreHostCtxKey = "mmr.ignore_host"
-const loggerCtxKey = "mmr.logger"
-
 type RequestCounter struct {
 	lastId uint64
 }
@@ -56,10 +52,10 @@ func (i *InstallMetadataRouter) ServeHTTP(w http.ResponseWriter, r *http.Request
 	})
 
 	ctx := r.Context()
-	ctx = context.WithValue(ctx, requestIdCtxKey, requestId)
-	ctx = context.WithValue(ctx, actionNameCtxKey, i.actionName)
-	ctx = context.WithValue(ctx, shouldIgnoreHostCtxKey, i.ignoreHost)
-	ctx = context.WithValue(ctx, loggerCtxKey, logger)
+	ctx = context.WithValue(ctx, common.ContextRequestId, requestId)
+	ctx = context.WithValue(ctx, common.ContextAction, i.actionName)
+	ctx = context.WithValue(ctx, common.ContextIgnoreHost, i.ignoreHost)
+	ctx = context.WithValue(ctx, common.ContextLogger, logger)
 	r = r.WithContext(ctx)
 
 	if i.next != nil {
@@ -68,7 +64,7 @@ func (i *InstallMetadataRouter) ServeHTTP(w http.ResponseWriter, r *http.Request
 }
 
 func GetActionName(r *http.Request) string {
-	x, ok := r.Context().Value(actionNameCtxKey).(string)
+	x, ok := r.Context().Value(common.ContextAction).(string)
 	if !ok {
 		return "<UNKNOWN>"
 	}
@@ -76,7 +72,7 @@ func GetActionName(r *http.Request) string {
 }
 
 func ShouldIgnoreHost(r *http.Request) bool {
-	x, ok := r.Context().Value(shouldIgnoreHostCtxKey).(bool)
+	x, ok := r.Context().Value(common.ContextIgnoreHost).(bool)
 	if !ok {
 		return false
 	}
@@ -84,7 +80,7 @@ func ShouldIgnoreHost(r *http.Request) bool {
 }
 
 func GetLogger(r *http.Request) *logrus.Entry {
-	x, ok := r.Context().Value(loggerCtxKey).(*logrus.Entry)
+	x, ok := r.Context().Value(common.ContextLogger).(*logrus.Entry)
 	if !ok {
 		return nil
 	}
diff --git a/api/_routers/03-host_detection.go b/api/_routers/03-host_detection.go
index 620518e8b40cfd74f1fd0a45ec3e1ed93819f5c3..48756ea87b0275a8f620a1e0801f2941a943a74a 100644
--- a/api/_routers/03-host_detection.go
+++ b/api/_routers/03-host_detection.go
@@ -13,13 +13,12 @@ import (
 	"github.com/sebest/xff"
 	"github.com/sirupsen/logrus"
 	"github.com/turt2live/matrix-media-repo/api/_responses"
+	"github.com/turt2live/matrix-media-repo/common"
 	"github.com/turt2live/matrix-media-repo/common/config"
 	"github.com/turt2live/matrix-media-repo/metrics"
 	"github.com/turt2live/matrix-media-repo/util"
 )
 
-const domainConfigCtxKey = "mmr.domain_config"
-
 type HostRouter struct {
 	next http.Handler
 }
@@ -78,7 +77,7 @@ func (h *HostRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	}
 
 	ctx := r.Context()
-	ctx = context.WithValue(ctx, domainConfigCtxKey, cfg)
+	ctx = context.WithValue(ctx, common.ContextDomainConfig, cfg)
 	r = r.WithContext(ctx)
 
 	if h.next != nil {
@@ -87,7 +86,7 @@ func (h *HostRouter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 }
 
 func GetDomainConfig(r *http.Request) *config.DomainRepoConfig {
-	x, ok := r.Context().Value(domainConfigCtxKey).(*config.DomainRepoConfig)
+	x, ok := r.Context().Value(common.ContextDomainConfig).(*config.DomainRepoConfig)
 	if !ok {
 		return nil
 	}
diff --git a/api/_routers/98-use-rcontext.go b/api/_routers/98-use-rcontext.go
index 5e682b701f9cbf3c2cd5ac79bb1a1e078e63ee92..bd6bf03bafe72a8a741959ab70a870f98eb7d5fc 100644
--- a/api/_routers/98-use-rcontext.go
+++ b/api/_routers/98-use-rcontext.go
@@ -22,8 +22,6 @@ import (
 	"github.com/turt2live/matrix-media-repo/util"
 )
 
-const statusCodeCtxKey = "mmr.status_code"
-
 type GeneratorFn = func(r *http.Request, ctx rcontext.RequestContext) interface{}
 
 type RContextRouter struct {
@@ -229,7 +227,7 @@ beforeParseDownload:
 }
 
 func GetStatusCode(r *http.Request) int {
-	x, ok := r.Context().Value(statusCodeCtxKey).(int)
+	x, ok := r.Context().Value(common.ContextStatusCode).(int)
 	if !ok {
 		return http.StatusOK
 	}
@@ -238,7 +236,7 @@ func GetStatusCode(r *http.Request) int {
 
 func writeStatusCode(w http.ResponseWriter, r *http.Request, statusCode int) *http.Request {
 	w.WriteHeader(statusCode)
-	return r.WithContext(context.WithValue(r.Context(), statusCodeCtxKey, statusCode))
+	return r.WithContext(context.WithValue(r.Context(), common.ContextStatusCode, statusCode))
 }
 
 func parseRange(r *http.Request, res *_responses.DownloadResponse) (bool, int64, int64, string) {
diff --git a/api/custom/exports.go b/api/custom/exports.go
index 84be0e32f189c1194e93c360c6e202505ae3a2f3..c54e328bdd5558a6a9c087af23a83cdea7077c43 100644
--- a/api/custom/exports.go
+++ b/api/custom/exports.go
@@ -186,7 +186,7 @@ func ViewExport(r *http.Request, rctx rcontext.RequestContext, user _apimeta.Use
 		return _responses.InternalServerError("failed to render template")
 	}
 
-	return &_responses.HtmlResponse{HTML: string(html.Bytes())}
+	return &_responses.HtmlResponse{HTML: html.String()}
 }
 
 func GetExportMetadata(r *http.Request, rctx rcontext.RequestContext, user _apimeta.UserInfo) interface{} {
diff --git a/api/custom/usage.go b/api/custom/usage.go
index c73b422cc7229ea45451fba51a1c01f0c4ef0dc4..21a271af2862576fb2812b451a67634d253e9724 100644
--- a/api/custom/usage.go
+++ b/api/custom/usage.go
@@ -37,7 +37,7 @@ type UserUsageEntry struct {
 	// Returned by per-user endpoints, where we can't count thumbnails
 	RawBytes     *MinimalUsageInfo `json:"raw_bytes"`
 	RawCounts    *MinimalUsageInfo `json:"raw_counts"`
-	UploadedMxcs []string          `json:"uploaded,flow"`
+	UploadedMxcs []string          `json:"uploaded"`
 }
 
 type MediaUsageEntry struct {
@@ -115,7 +115,7 @@ func GetUserUsage(r *http.Request, rctx rcontext.RequestContext, user _apimeta.U
 
 	var records []*database.DbMedia
 	var err error
-	if userIds == nil || len(userIds) == 0 {
+	if len(userIds) == 0 {
 		records, err = db.GetByOrigin(serverName)
 	} else {
 		records, err = db.GetByOriginUsers(serverName, userIds)
@@ -174,7 +174,7 @@ func GetUploadsUsage(r *http.Request, rctx rcontext.RequestContext, user _apimet
 
 	var records []*database.DbMedia
 	var err error
-	if mxcs == nil || len(mxcs) == 0 {
+	if len(mxcs) == 0 {
 		records, err = db.GetByOrigin(serverName)
 	} else {
 		split := make([]string, 0)
diff --git a/api/unstable/info.go b/api/unstable/info.go
index 7335c8ed9f71788767b361db1ec3bf814634f5b5..b42cbb506dd592c58d79ed95dfe62e4b9936068d 100644
--- a/api/unstable/info.go
+++ b/api/unstable/info.go
@@ -142,7 +142,7 @@ func MediaInfo(r *http.Request, rctx rcontext.RequestContext, user _apimeta.User
 		return _responses.InternalServerError("Unexpected Error")
 	}
 
-	if thumbs != nil && len(thumbs) > 0 {
+	if len(thumbs) > 0 {
 		infoThumbs := make([]*mediaInfoThumbnail, 0)
 		for _, thumb := range thumbs {
 			infoThumbs = append(infoThumbs, &mediaInfoThumbnail{
diff --git a/archival/entity_export.go b/archival/entity_export.go
index 0d8330b3f67bcb496d0b7579d81a2c013cc15d31..cfe30ec6dae1f795a108f0164f353923dfdbdf2b 100644
--- a/archival/entity_export.go
+++ b/archival/entity_export.go
@@ -77,6 +77,9 @@ func ExportEntityData(ctx rcontext.RequestContext, exportId string, entityId str
 			S3Url:       s3url,
 			UserId:      media.UserId,
 		})
+		if err != nil {
+			return err
+		}
 		if exportedHash != media.Sha256Hash {
 			ctx.Log.Warnf("%s should have had hash %s but it had %s when placed in the archive", mxc, media.Sha256Hash, exportedHash)
 		}
diff --git a/archival/v2archive/writer.go b/archival/v2archive/writer.go
index 7e11138aedb0f841b3cb024d0d29bbd5cb069e4c..e186dd60d0c533c1e6eb9439531227204bfa9d76 100644
--- a/archival/v2archive/writer.go
+++ b/archival/v2archive/writer.go
@@ -153,6 +153,9 @@ func (w *ArchiveWriter) AppendMedia(file io.ReadCloser, info MediaInfo) (string,
 	createTime := util.FromMillis(info.CreationTs)
 
 	size, sha256hash, err := w.putFile(br.GetRewoundReader(), internalName, createTime)
+	if err != nil {
+		return "", err
+	}
 	w.mediaManifest[util.MxcUri(info.Origin, info.MediaId)] = &ManifestRecord{
 		FileName:     info.FileName,
 		ArchivedName: internalName,
diff --git a/cmd/export_synapse_for_import/main.go b/cmd/export_synapse_for_import/main.go
index d0685bcf436823a96a6ad7c4c3459a0eb345d512..fa0f5032e26c18bef87663c1c59adfc4f0c7cc6d 100644
--- a/cmd/export_synapse_for_import/main.go
+++ b/cmd/export_synapse_for_import/main.go
@@ -17,7 +17,7 @@ import (
 	"github.com/turt2live/matrix-media-repo/common/version"
 	"github.com/turt2live/matrix-media-repo/homeserver_interop/synapse"
 	"github.com/turt2live/matrix-media-repo/util"
-	"golang.org/x/crypto/ssh/terminal"
+	"golang.org/x/term"
 )
 
 func main() {
@@ -45,14 +45,14 @@ func main() {
 
 	var realPsqlPassword string
 	if *postgresPassword == "" {
-		if !terminal.IsTerminal(int(os.Stdin.Fd())) {
+		if !term.IsTerminal(int(os.Stdin.Fd())) {
 			fmt.Println("Sorry, your terminal does not support reading passwords. Please supply a -dbPassword or use a different terminal.")
 			fmt.Println("If you're on Windows, try using a plain Command Prompt window instead of a bash-like terminal.")
 			os.Exit(1)
 			return // for good measure
 		}
 		fmt.Printf("Postgres password: ")
-		pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
+		pass, err := term.ReadPassword(int(os.Stdin.Fd()))
 		if err != nil {
 			panic(err)
 		}
diff --git a/cmd/import_synapse/main.go b/cmd/import_synapse/main.go
index e3eee8346aa6f71c944c410eabc255a89832b261..ef086d1e339ae15cbb52943fd1132bdb3faae2bc 100644
--- a/cmd/import_synapse/main.go
+++ b/cmd/import_synapse/main.go
@@ -23,7 +23,7 @@ import (
 	"github.com/turt2live/matrix-media-repo/homeserver_interop/synapse"
 	"github.com/turt2live/matrix-media-repo/pipelines/pipeline_upload"
 	"github.com/turt2live/matrix-media-repo/util/ids"
-	"golang.org/x/crypto/ssh/terminal"
+	"golang.org/x/term"
 )
 
 func main() {
@@ -57,14 +57,14 @@ func main() {
 
 	var realPsqlPassword string
 	if *postgresPassword == "" {
-		if !terminal.IsTerminal(int(os.Stdin.Fd())) {
+		if !term.IsTerminal(int(os.Stdin.Fd())) {
 			fmt.Println("Sorry, your terminal does not support reading passwords. Please supply a -dbPassword or use a different terminal.")
 			fmt.Println("If you're on Windows, try using a plain Command Prompt window instead of a bash-like terminal.")
 			os.Exit(1)
 			return // for good measure
 		}
 		fmt.Printf("Postgres password: ")
-		pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
+		pass, err := term.ReadPassword(int(os.Stdin.Fd()))
 		if err != nil {
 			panic(err)
 		}
diff --git a/cmd/media_repo/main.go b/cmd/media_repo/main.go
index 04d75afa870ba6f05f52d509f32f9629ef10ba52..46800a9c2b802e1ba0709f23e7ebec901f1e7177 100644
--- a/cmd/media_repo/main.go
+++ b/cmd/media_repo/main.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"os"
 	"os/signal"
+	"syscall"
 	"time"
 
 	"github.com/fsnotify/fsnotify"
@@ -101,7 +102,7 @@ func main() {
 
 	// Set up a listener for SIGINT
 	stop := make(chan os.Signal, 1)
-	signal.Notify(stop, os.Interrupt, os.Kill)
+	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
 	selfStop := false
 	go func() {
 		defer close(stop)
diff --git a/cmd/plugin_antispam_ocr/main.go b/cmd/plugin_antispam_ocr/main.go
index b88033633bbe75e31f9d9d2159156b665757b52d..c5fa6b2587462c40ce965eb50238a8aa74f23e3f 100644
--- a/cmd/plugin_antispam_ocr/main.go
+++ b/cmd/plugin_antispam_ocr/main.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"encoding/base64"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"image"
 	"io"
@@ -147,7 +146,7 @@ func (a *AntispamOCR) CheckForSpam(b64 string, filename string, contentType stri
 		return false, err
 	}
 	if res.StatusCode != http.StatusOK {
-		return false, errors.New(fmt.Sprintf("unexpected status code: %d", res.StatusCode))
+		return false, fmt.Errorf("unexpected status code: %d", res.StatusCode)
 	}
 	ocr := strings.ToLower(resp["result"].(string))
 
diff --git a/cmd/s3_consistency_check/main.go b/cmd/s3_consistency_check/main.go
index 3cf5b4bfe25b85e431953968567c661e4f5c32cf..5bc1c95422c0775a71c964e362ad6cb102a82e2d 100644
--- a/cmd/s3_consistency_check/main.go
+++ b/cmd/s3_consistency_check/main.go
@@ -104,7 +104,6 @@ func main() {
 	}
 
 	f, err := os.Create(*outFile)
-	defer f.Close()
 	if err != nil {
 		panic(err)
 	}
@@ -114,5 +113,9 @@ func main() {
 			panic(err)
 		}
 	}
+	err = f.Close()
+	if err != nil {
+		panic(err)
+	}
 	logrus.Info("Done!")
 }
diff --git a/common/config/access.go b/common/config/access.go
index 8822a73d11c85bce1f36a43529e766eb0c90757f..6b1bab4423d1d5c7d0fde5478bd39b3e0c376869 100644
--- a/common/config/access.go
+++ b/common/config/access.go
@@ -34,7 +34,7 @@ func reloadConfig() (*MainRepoConfig, map[string]*DomainRepoConfig, error) {
 	domainConfs := make(map[string]*DomainRepoConfig)
 
 	// Write a default config if the one given doesn't exist
-	info, err := os.Stat(Path)
+	_, err := os.Stat(Path)
 	exists := err == nil || !os.IsNotExist(err)
 	if !exists {
 		fmt.Println("Generating new configuration...")
@@ -60,7 +60,7 @@ func reloadConfig() (*MainRepoConfig, map[string]*DomainRepoConfig, error) {
 	}
 
 	// Get new info about the possible directory after creating
-	info, err = os.Stat(Path)
+	info, err := os.Stat(Path)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -241,10 +241,7 @@ func DomainConfigFrom(c MainRepoConfig) DomainRepoConfig {
 
 func UniqueDatastores() []DatastoreConfig {
 	confs := make([]DatastoreConfig, 0)
-
-	for _, dsc := range Get().DataStores {
-		confs = append(confs, dsc)
-	}
+	confs = append(confs, Get().DataStores...)
 
 	for _, d := range AllDomains() {
 		for _, dsc := range d.DataStores {
diff --git a/common/config/watch.go b/common/config/watch.go
index fb28fdf1043a561b42889ffd612a766096b74f5e..5e9d3bde1f51f884ad4d55d5982ddd73e7ae9574 100644
--- a/common/config/watch.go
+++ b/common/config/watch.go
@@ -119,11 +119,7 @@ func onFileChanged() {
 }
 
 func hasWebFeatureChanged(configNew *MainRepoConfig, configNow *MainRepoConfig) bool {
-	if configNew.Features.MSC2448Blurhash.Enabled != configNow.Features.MSC2448Blurhash.Enabled {
-		return true
-	}
-
-	return false
+	return configNew.Features.MSC2448Blurhash.Enabled != configNow.Features.MSC2448Blurhash.Enabled
 }
 
 func hasRedisShardConfigChanged(configNew *MainRepoConfig, configNow *MainRepoConfig) bool {
diff --git a/common/context.go b/common/context.go
new file mode 100644
index 0000000000000000000000000000000000000000..629249e5cd6e0a2cbf442d13bf2ad2779ae8b5f5
--- /dev/null
+++ b/common/context.go
@@ -0,0 +1,14 @@
+package common
+
+type MmrContextKey string
+
+const (
+	ContextLogger       MmrContextKey = "mmr.logger"
+	ContextIgnoreHost   MmrContextKey = "mmr.ignore_host"
+	ContextAction       MmrContextKey = "mmr.action"
+	ContextRequest      MmrContextKey = "mmr.request"
+	ContextRequestId    MmrContextKey = "mmr.request_id"
+	ContextServerConfig MmrContextKey = "mmr.serverConfig"
+	ContextDomainConfig MmrContextKey = "mmr.domain_config"
+	ContextStatusCode   MmrContextKey = "mmr.status_code"
+)
diff --git a/common/rcontext/request_context.go b/common/rcontext/request_context.go
index 9965e3bc3a52d6fb059164531975ce0dbd33c635..4311edd514eeb73088d7376846c2ec0de61627fb 100644
--- a/common/rcontext/request_context.go
+++ b/common/rcontext/request_context.go
@@ -5,6 +5,7 @@ import (
 	"net/http"
 
 	"github.com/sirupsen/logrus"
+	"github.com/turt2live/matrix-media-repo/common"
 	"github.com/turt2live/matrix-media-repo/common/config"
 )
 
@@ -35,20 +36,20 @@ type RequestContext struct {
 	context.Context
 
 	// These are also stored on the context object itself
-	Log     *logrus.Entry           // mmr.logger
-	Config  config.DomainRepoConfig // mmr.serverConfig
-	Request *http.Request           // mmr.request
+	Log     *logrus.Entry           // common.ContextLogger
+	Config  config.DomainRepoConfig // common.ContextServerConfig
+	Request *http.Request           // common.ContextRequest
 }
 
 func (c RequestContext) populate() RequestContext {
-	c.Context = context.WithValue(c.Context, "mmr.logger", c.Log)
-	c.Context = context.WithValue(c.Context, "mmr.serverConfig", c.Config)
-	c.Context = context.WithValue(c.Context, "mmr.request", c.Request)
+	c.Context = context.WithValue(c.Context, common.ContextLogger, c.Log)
+	c.Context = context.WithValue(c.Context, common.ContextServerConfig, c.Config)
+	c.Context = context.WithValue(c.Context, common.ContextRequest, c.Request)
 	return c
 }
 
 func (c RequestContext) ReplaceLogger(log *logrus.Entry) RequestContext {
-	ctx := context.WithValue(c.Context, "mmr.logger", log)
+	ctx := context.WithValue(c.Context, common.ContextLogger, log)
 	return RequestContext{
 		Context: ctx,
 		Log:     log,
diff --git a/datastores/pick.go b/datastores/pick.go
index 748ea0f4e0a59fe67106fee45a76f9c683030b36..30bba75fd169da16e0cd915b2c2ef83ff8f74073 100644
--- a/datastores/pick.go
+++ b/datastores/pick.go
@@ -17,7 +17,7 @@ func Pick(ctx rcontext.RequestContext, kind Kind) (config.DatastoreConfig, error
 		usable = append(usable, conf)
 	}
 
-	if len(usable) < 0 {
+	if len(usable) == 0 {
 		return config.DatastoreConfig{}, errors.New("unable to locate a usable datastore")
 	}
 	if len(usable) == 1 {
diff --git a/datastores/upload.go b/datastores/upload.go
index 813300b305502fd48c179c1f7f1beccf2fedfc99..485b1c7de8a68294a00d0b114bddcbe07b343656 100644
--- a/datastores/upload.go
+++ b/datastores/upload.go
@@ -125,7 +125,7 @@ func Upload(ctx rcontext.RequestContext, ds config.DatastoreConfig, data io.Read
 		if err = Remove(ctx, ds, objectName); err != nil {
 			ctx.Log.Warn("Error deleting upload (delete attempted due to persistence error): ", err)
 		}
-		return "", errors.New(fmt.Sprintf("upload size mismatch: expected %d got %d bytes", size, uploadedBytes))
+		return "", fmt.Errorf("upload size mismatch: expected %d got %d bytes", size, uploadedBytes)
 	}
 
 	uploadedHash := hex.EncodeToString(hasher.Sum(nil))
@@ -133,7 +133,7 @@ func Upload(ctx rcontext.RequestContext, ds config.DatastoreConfig, data io.Read
 		if err = Remove(ctx, ds, objectName); err != nil {
 			ctx.Log.Warn("Error deleting upload (delete attempted due to persistence error): ", err)
 		}
-		return "", errors.New(fmt.Sprintf("upload hash mismatch: expected %s got %s", sha256hash, uploadedHash))
+		return "", fmt.Errorf("upload hash mismatch: expected %s got %s", sha256hash, uploadedHash)
 	}
 
 	return objectName, nil
diff --git a/homeserver_interop/synapse/api.go b/homeserver_interop/synapse/api.go
index 76146028d8dd400df1a715a8f2075ece8f98df51..08d3d5e671c958e329c3d68458c2109ff6ad8840 100644
--- a/homeserver_interop/synapse/api.go
+++ b/homeserver_interop/synapse/api.go
@@ -10,7 +10,7 @@ type SynUserStatRecord struct {
 }
 
 type SynUserStatsResponse struct {
-	Users     []*SynUserStatRecord `json:"users,flow"`
+	Users     []*SynUserStatRecord `json:"users"`
 	NextToken int64                `json:"next_token,omitempty"`
 	Total     int64                `json:"total"`
 }
diff --git a/matrix/federation.go b/matrix/federation.go
index 0ddda378dfd09d8fe28e5f8addabb00b204dddce..940d761112593117921a07bfa386112abdb51c1a 100644
--- a/matrix/federation.go
+++ b/matrix/federation.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"crypto/tls"
 	"encoding/json"
-	"errors"
 	"fmt"
 	"net"
 	"net/http"
@@ -268,7 +267,7 @@ func FederatedGet(url string, realHost string, ctx rcontext.RequestContext) (*ht
 			return err
 		}
 		if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNotFound {
-			return errors.New(fmt.Sprintf("response not ok: %d", resp.StatusCode))
+			return fmt.Errorf("response not ok: %d", resp.StatusCode)
 		}
 		return nil
 	}, 1*time.Minute)
diff --git a/pipelines/pipeline_upload/pipeline.go b/pipelines/pipeline_upload/pipeline.go
index dd534ef837a4cb34b5b49a041cd9c591b26ceacd..ba53322e3a8caeb6977126fa9aa43ca9c2ecdbec 100644
--- a/pipelines/pipeline_upload/pipeline.go
+++ b/pipelines/pipeline_upload/pipeline.go
@@ -128,6 +128,9 @@ func Execute(ctx rcontext.RequestContext, origin string, mediaId string, r io.Re
 		},
 	}
 	record, perfect, err := upload.FindRecord(ctx, sha256hash, userId, contentType, fileName)
+	if err != nil {
+		return nil, err
+	}
 	if record != nil {
 		// We already had this record in some capacity
 		if perfect && !mustUseMediaId {
diff --git a/test/test_internals/deps_mmr.go b/test/test_internals/deps_mmr.go
index ff098637630dcd83928b9e16d19939ab7600bafb..ea537c837c6bb3f70589ac47a48d8609242c51f4 100644
--- a/test/test_internals/deps_mmr.go
+++ b/test/test_internals/deps_mmr.go
@@ -31,10 +31,9 @@ type mmrTmplArgs struct {
 }
 
 type mmrContainer struct {
-	ctx                   context.Context
-	container             testcontainers.Container
-	tmpConfigPath         string
-	tmpExternalConfigPath string
+	ctx           context.Context
+	container     testcontainers.Container
+	tmpConfigPath string
 
 	HttpUrl   string
 	MachineId int
diff --git a/test/test_internals/util_client.go b/test/test_internals/util_client.go
index 0bb56992e54c2787156329d6e49a50a79218fcb9..443ca50742c5eb6928b700276054f1f0a1070272 100644
--- a/test/test_internals/util_client.go
+++ b/test/test_internals/util_client.go
@@ -42,7 +42,7 @@ func (c *MatrixClient) DoReturnJson(method string, endpoint string, qs url.Value
 		if err != nil {
 			return err
 		}
-		return errors.New(fmt.Sprintf("%d : %s", res.StatusCode, string(b)))
+		return fmt.Errorf("%d : %s", res.StatusCode, string(b))
 	}
 
 	decoder := json.NewDecoder(res.Body)
@@ -84,6 +84,6 @@ func (c *MatrixClient) DoRaw(method string, endpoint string, qs url.Values, cont
 		req.Header.Set("Authorization", "Bearer "+c.AccessToken)
 	}
 
-	log.Println(fmt.Sprintf("[HTTP] [Auth=%s] [Host=%s] %s %s", c.AccessToken, c.ServerName, req.Method, req.URL.String()))
+	log.Printf("[HTTP] [Auth=%s] [Host=%s] %s %s", c.AccessToken, c.ServerName, req.Method, req.URL.String())
 	return http.DefaultClient.Do(req)
 }
diff --git a/test/upload_suite_test.go b/test/upload_suite_test.go
index 97070af9bd997abd79adb77e43c44a982b2cf18a..157192a7424227fc8f7d02bbc000f42bac02a2d5 100644
--- a/test/upload_suite_test.go
+++ b/test/upload_suite_test.go
@@ -200,8 +200,8 @@ func (s *UploadTestSuite) TestUploadSpam() {
 	uploadWaiter := new(sync.WaitGroup)
 	mediaIds := new(sync.Map)
 	for i := 0; i < concurrentUploads; i++ {
+		uploadWaiter.Add(1)
 		go func(j int) {
-			uploadWaiter.Add(1)
 			defer uploadWaiter.Done()
 
 			img := images[j]
diff --git a/thumbnailing/i/01-factories.go b/thumbnailing/i/01-factories.go
index e8410865c51bc9b1e0fa54cb6a262d8abd88a2b1..4e2fc6e08a2cbfc2d61b8992fe92db6e6824e639 100644
--- a/thumbnailing/i/01-factories.go
+++ b/thumbnailing/i/01-factories.go
@@ -43,9 +43,7 @@ func GetGenerator(img io.Reader, contentType string, needsAnimation bool) (Gener
 func GetSupportedContentTypes() []string {
 	a := make([]string, 0)
 	for _, d := range generators {
-		for _, c := range d.supportedContentTypes() {
-			a = append(a, c)
-		}
+		a = append(a, d.supportedContentTypes()...)
 	}
 	return a
 }
diff --git a/thumbnailing/i/jpg.go b/thumbnailing/i/jpg.go
index 82eeb988c173276cd8f2ae4b873ff062414f57a9..adc770041d5bd2ff72804ca195914e44d82599ed 100644
--- a/thumbnailing/i/jpg.go
+++ b/thumbnailing/i/jpg.go
@@ -44,7 +44,7 @@ func (d jpgGenerator) GenerateThumbnail(b io.Reader, contentType string, width i
 	}
 
 	var shouldThumbnail bool
-	shouldThumbnail, width, height, animated, method = u.AdjustProperties(src, width, height, animated, false, method)
+	shouldThumbnail, width, height, _, method = u.AdjustProperties(src, width, height, animated, false, method)
 	if !shouldThumbnail {
 		return nil, nil
 	}
diff --git a/thumbnailing/u/exif.go b/thumbnailing/u/exif.go
index 57f1ed2d5f3db19b51ca4826975fbb7f3f7adbdc..b6b65176d26483bb7f350d788cd2a3cd5c5da9ff 100644
--- a/thumbnailing/u/exif.go
+++ b/thumbnailing/u/exif.go
@@ -53,7 +53,7 @@ func GetExifOrientation(img io.Reader) (*ExifOrientation, error) {
 	}
 
 	if orientation < 1 || orientation > 8 {
-		return nil, errors.New(fmt.Sprintf("orientation out of range: %d", orientation))
+		return nil, fmt.Errorf("orientation out of range: %d", orientation)
 	}
 
 	flipHorizontal := orientation < 5 && (orientation%2) == 0
diff --git a/util/mime.go b/util/mime.go
index 6005858da191c9a3761e430b255d6fe930b1ce0f..5887654923f64c1101e7b8eab9ad69eb10c87a3e 100644
--- a/util/mime.go
+++ b/util/mime.go
@@ -11,7 +11,7 @@ func FixContentType(ct string) string {
 
 func ExtensionForContentType(ct string) string {
 	exts, _ := mime.ExtensionsByType(ct)
-	if exts != nil && len(exts) > 0 {
+	if len(exts) > 0 {
 		return exts[0]
 	}
 	return ".bin"
diff --git a/util/readers/temp_file_closer.go b/util/readers/temp_file_closer.go
index 99b9303b987ad8dea6488d7e3d7aab7cf5310559..c5956259eac4e53a226b4068a4e71f824b6ff247 100644
--- a/util/readers/temp_file_closer.go
+++ b/util/readers/temp_file_closer.go
@@ -26,10 +26,10 @@ func (c *TempFileCloser) Close() error {
 	if c.closed {
 		return nil
 	}
-	var upstreamErr error
-	if upstreamErr = c.upstream.Close(); upstreamErr != nil {
-		// don't return the error yet because we want to try to delete the temp file
-	}
+
+	upstreamErr := c.upstream.Close()
+	// don't return upstreamErr yet because we want to try to delete the temp file
+
 	var err error
 	if err = os.Remove(c.fname); err != nil && !os.IsNotExist(err) {
 		return err