{"record":{"id":"a05664cf31559a35","repo":"stride3d/stride","slug":"the-character-character-character-upload-has-been-requested","errorCode":null,"errorMessage":"The character '{character.Character}' upload has been requested while its current glyph is valid.","messagePattern":"The character '(.+?)' upload has been requested while its current glyph is valid\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/engine/Stride.Graphics/Font/FontCacheManager.cs","lineNumber":70,"sourceCode":"        {\n            foreach (var character in cachedCharacters)\n                character.IsBitmapUploaded = false;\n            cachedCharacters.Clear();\n\n            packer.Clear(cacheTextures[0].ViewWidth, cacheTextures[0].ViewHeight);\n        }\n        \n        /// <summary>\n        /// Upload a character's bitmap into the current cache.\n        /// </summary>\n        /// <param name=\"character\">The character specifications corresponding to the bitmap</param>\n        public void UploadCharacterBitmap(CommandList commandList, CharacterSpecification character)\n        {\n            if (character.Bitmap == null)\n                throw new ArgumentNullException(\"character\");\n\n            if (character.IsBitmapUploaded)\n                throw new InvalidOperationException($\"The character '{character.Character}' upload has been requested while its current glyph is valid.\");\n\n            var targetSize = new Int2(character.Bitmap.Width, character.Bitmap.Rows);\n            if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))\n            {\n                // not enough space to place the new character -> remove less used characters and try again\n                RemoveLessUsedCharacters();\n                if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))\n                {\n                    // memory is too fragmented in order to place the new character -> clear all the characters and restart.\n                    // TODO: This is invalid, we might delete character from current frame!\n                    ClearCache();\n                    if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))\n                        throw new InvalidOperationException(\"The rendered character is too big for the cache texture\");\n                }\n            }\n            // Upload the bitmap to the atlas texture, with a 1px transparent border extending\n            // beyond the allocated region to clear any stale pixels from previously freed glyphs.\n            // This overlaps into neighbors' transparent borders (which are also zeroed), so no","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/engine/Stride.Graphics/Font/FontCacheManager.cs#L52-L88","documentation":"The font atlas cache refuses to upload a glyph whose bitmap was already uploaded for the current valid glyph state. If CharacterSpecification.IsBitmapUploaded is true, re-requesting an upload indicates duplicate cache management, so it throws InvalidOperationException naming the character.","triggerScenarios":"Calling UploadCharacterBitmap twice for the same character while its glyph is still valid (not evicted and not invalidated).","commonSituations":"Double-enqueueing characters during the same frame (e.g. drawing the same text twice through separate code paths that both force uploads); cache invalidation logic that fails to reset IsBitmapUploaded or clears without resetting state.","solutions":["Check character.IsBitmapUploaded before calling UploadCharacterBitmap and skip if true","Ensure only one code path owns uploading characters per frame","If the glyph must be re-uploaded, invalidate the character's glyph state first so IsBitmapUploaded resets","Investigate unexpected cache clear/invalidation logic that leaves IsBitmapUploaded inconsistent"],"exampleFix":"// before\ncacheManager.UploadCharacterBitmap(commandList, character);\n// after\nif (!character.IsBitmapUploaded)\n    cacheManager.UploadCharacterBitmap(commandList, character);","handlingStrategy":"validation","validationCode":"if (character.IsBitmapUploaded) return; // already in atlas","typeGuard":"bool NeedsUpload(CharacterSpecification c) => c.Bitmap != null && !c.IsBitmapUploaded;","tryCatchPattern":"try { cache.UploadCharacterBitmap(commandList, character); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"upload has been requested\"))\n{\n    // glyph already valid in atlas; safe to ignore\n}","preventionTips":["Single choke point for glyph uploads to prevent duplicates","Check IsBitmapUploaded before every upload call","Ensure cache clears also reset per-character upload state"],"tags":["fonts","invalid-state","atlas","duplicate-upload"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}