{"record":{"id":"f2ae2377e5e98ff8","repo":"dutchcoders/transfer.sh","slug":"deletion-token-doesn-t-match","errorCode":null,"errorMessage":"deletion token doesn't match","messagePattern":"deletion token doesn't match","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/handlers.go","lineNumber":924,"sourceCode":"func (s *Server) checkDeletionToken(ctx context.Context, deletionToken, token, filename string) error {\n\ts.lock(token, filename)\n\tdefer s.unlock(token, filename)\n\n\tvar metadata metadata\n\n\tr, _, err := s.storage.Get(ctx, token, fmt.Sprintf(\"%s.metadata\", filename), nil)\n\tdefer storage.CloseCheck(r)\n\n\tif s.storage.IsNotExist(err) {\n\t\treturn errors.New(\"metadata doesn't exist\")\n\t} else if err != nil {\n\t\treturn err\n\t}\n\n\tif err := json.NewDecoder(r).Decode(&metadata); err != nil {\n\t\treturn err\n\t} else if metadata.DeletionToken != deletionToken {\n\t\treturn errors.New(\"deletion token doesn't match\")\n\t}\n\n\treturn nil\n}\n\nfunc (s *Server) purgeHandler() {\n\tticker := time.NewTicker(s.purgeInterval)\n\tgo func() {\n\t\tfor {\n\t\t\t<-ticker.C\n\t\t\terr := s.storage.Purge(context.TODO(), s.purgeDays)\n\t\t\tif err != nil {\n\t\t\t\ts.logger.Printf(\"error cleaning up expired files: %v\", err)\n\t\t\t}\n\t\t}\n\t}()\n}\n","sourceCodeStart":906,"sourceCodeEnd":942,"githubUrl":"https://github.com/dutchcoders/transfer.sh/blob/c37bfd95797fd6da8a6da53fc13d191994b3f687/server/handlers.go#L906-L942","documentation":"After successfully loading metadata, checkDeletionToken compares metadata.DeletionToken with the deletionToken supplied by the caller. On mismatch it returns this error and refuses to delete the file. It is an authorization failure: the delete request did not present the correct secret token recorded at upload time.","triggerScenarios":"DELETE request whose X-Url-Delete header (or URL-embedded deletion token) does not equal the DeletionToken stored in the file's .metadata, including missing header, empty string, or a token belonging to a different file.","commonSituations":"Losing the original deletion token returned in the X-Url-Delete response header at upload time; copying the URL token instead of the deletion token; shell stripping/altering the header value; attempting to delete someone else's upload.","solutions":["Use the exact X-Url-Delete value returned when the file was uploaded.","Ensure the header is sent correctly (quote it in the shell; confirm it is not stripped by proxies/CDNs).","If the token is lost, the file can only be removed by storage administrators directly from the backend or by waiting for expiry/purge.","Re-upload to obtain a fresh file plus deletion token if the original cannot be recovered."],"exampleFix":"// before\ncurl -X DELETE https://host/token/f.txt -H 'X-Url-Delete: guessed'\n// after\ncurl -X DELETE https://host/token/f.txt -H 'X-Url-Delete: <token-printed-at-upload>'","handlingStrategy":"validation","validationCode":"// only send DELETE when a deletion token is present and non-empty\nif deletionToken == \"\" {\n\treturn errors.New(\"refusing to delete: deletion token unknown\")\n}","typeGuard":"func hasDeletionToken(tok string) bool { return len(tok) > 0 }","tryCatchPattern":"resp, err := doDelete(token, file, delToken)\nif err == nil && resp.StatusCode != http.StatusOK {\n\tb, _ := io.ReadAll(resp.Body)\n\tif strings.Contains(string(b), \"deletion token doesn't match\") {\n\t\t// stop retrying with wrong credentials; recover token or abandon\n\t}\n}","preventionTips":["Record the X-Url-Delete response header at upload time in a secure store.","Never confuse the URL token with the deletion token — they are different secrets.","Quote the header value in shell commands to avoid whitespace stripping."],"tags":["authorization","delete","token","file-transfer"],"backgroundTag":"auth-token-mismatch","analyzedSha":"c37bfd95797fd6da8a6da53fc13d191994b3f687","analyzedAt":"2026-09-05T10:21:07.548Z","contentChangedAt":"2026-09-05T10:21:07.548Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}