{"record":{"id":"aee75858c70c4130","repo":"Kareadita/Kavita","slug":"errors-font-manual-upload","errorCode":null,"errorMessage":"errors.font-manual-upload","messagePattern":"errors\\.font-manual-upload","errorType":"exception","errorClass":"KavitaException","httpStatus":null,"severity":"error","filePath":"Kavita.Services/FontService.cs","lineNumber":92,"sourceCode":"    public required int nanos { get; init; }\n}\n\npublic class FontService(IDirectoryService directoryService, IUnitOfWork unitOfWork, ILogger<FontService> logger,\n    IUrlValidationService urlValidationService)\n    : IFontService\n{\n    private const string SupportedFontUrlPrefix = \"https://fonts.google.com/\";\n    private const string DownloadFontUrlPrefix = \"https://fonts.google.com/download/list?family=\";\n    private const string GoogleFontsInvalidJsonPrefix = \")]}'\";\n\n\n    public async Task<EpubFont> CreateFontFromFileAsync(string path, CancellationToken ct = default)\n    {\n        // Validate that font was uploaded\n        if (!directoryService.FileSystem.File.Exists(path))\n        {\n            logger.LogInformation(\"Unable to create font from manual upload as font not in temp\");\n            throw new KavitaException(\"errors.font-manual-upload\");\n        }\n\n        // Extract filename and then parse font object from the filename\n        var fileName = directoryService.FileSystem.FileInfo.New(path).Name;\n        var font = Parser.ParseEpubFontFromFilename(fileName);\n\n        var dbFont = await unitOfWork.EpubFontRepository.GetFontByNameAsync(font.Name, ct);\n\n        // Check if font name is already present in database\n        // If it is, return the one that is already in the database.\n        if (dbFont != null)\n        {\n            return dbFont;\n        }\n\n        // Copy file from temp directory to EpubFontDirectory\n        directoryService.CopyFileToDirectory(path, directoryService.EpubFontDirectory);\n","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/FontService.cs#L74-L110","documentation":"Thrown by FontService.CreateFontFromFileAsync when the uploaded font file does not exist at the given temp path. The check directoryService.FileSystem.File.Exists(path) returns false, meaning either the upload did not complete, the temp file was cleaned up, or the path is wrong. It is a KavitaException (UI-facing, not Sentry-reported).","triggerScenarios":"Font upload was interrupted or failed before the file reached the temp directory; the temp cleanup task ran between upload completion and this method call; the path passed does not match where the upload middleware stored the file; file size exceeded upload limits and was silently dropped.","commonSituations":"Upload timeout or network interruption during font file upload; reverse proxy (nginx, Cloudflare) with a body size limit smaller than the font file; temp directory configured on a volume with insufficient space; anti-virus or security software quarantining font files.","solutions":["Re-upload the font file and ensure the upload completes without error","Check the reverse proxy and Kavita's max upload size limits are large enough for the font file","Verify the temp directory has sufficient disk space and write permissions","Inspect server logs for upload errors or temp file cleanup messages preceding this error"],"exampleFix":"// No code fix needed — this is an operational/upload issue.\n// Ensure the upload pipeline delivers the file to temp before this method runs.\n// Check: ls -la /temp/font/path/ to confirm the file arrived.","handlingStrategy":"validation","validationCode":"// Verify the uploaded font file exists in temp before processing:\n// if (!directoryService.FileSystem.File.Exists(path)) {\n//     return BadRequest(\"Font upload failed — no file received. Please try uploading again.\");\n// }","typeGuard":null,"tryCatchPattern":"// try {\n//     var font = await fontService.CreateFontFromFileAsync(path, ct);\n//     return Ok(font);\n// } catch (KavitaException ex) when (ex.Message == \"errors.font-manual-upload\") {\n//     return BadRequest(new { error = \"Font file was not received. The upload may have failed. Please retry.\" });\n// }","preventionTips":["Configure reverse proxy (nginx/Cloudflare) body size limits to accommodate font files","Verify temp directory has sufficient space and write permissions","Check upload completion status in the client before proceeding to the font creation step","Monitor temp directory cleanup schedules to ensure uploaded files are not removed prematurely"],"tags":["font","upload","filesystem","temp-file","missing-file"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}