stride3d/stride · error · InvalidOperationException

The character ' ' upload has been requested while its…

Error message

The character '{character.Character}' upload has been requested while its current glyph is valid.

What it means

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.

Solutions

  1. Check character.IsBitmapUploaded before calling UploadCharacterBitmap and skip if true
  2. Ensure only one code path owns uploading characters per frame
  3. If the glyph must be re-uploaded, invalidate the character's glyph state first so IsBitmapUploaded resets
  4. Investigate unexpected cache clear/invalidation logic that leaves IsBitmapUploaded inconsistent

Example fix

// before
cacheManager.UploadCharacterBitmap(commandList, character);
// after
if (!character.IsBitmapUploaded)
    cacheManager.UploadCharacterBitmap(commandList, character);
Defensive patterns

Strategy: validation

Validate before calling

if (character.IsBitmapUploaded) return; // already in atlas

Type guard

bool NeedsUpload(CharacterSpecification c) => c.Bitmap != null && !c.IsBitmapUploaded;

Try / catch

try { cache.UploadCharacterBitmap(commandList, character); }
catch (InvalidOperationException ex) when (ex.Message.Contains("upload has been requested"))
{
    // glyph already valid in atlas; safe to ignore
}

Prevention

When it happens

Trigger: Calling UploadCharacterBitmap twice for the same character while its glyph is still valid (not evicted and not invalidated).

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/a05664cf31559a35. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Graphics/Font/FontCacheManager.cs:70

        {
            foreach (var character in cachedCharacters)
                character.IsBitmapUploaded = false;
            cachedCharacters.Clear();

            packer.Clear(cacheTextures[0].ViewWidth, cacheTextures[0].ViewHeight);
        }
        
        /// <summary>
        /// Upload a character's bitmap into the current cache.
        /// </summary>
        /// <param name="character">The character specifications corresponding to the bitmap</param>
        public void UploadCharacterBitmap(CommandList commandList, CharacterSpecification character)
        {
            if (character.Bitmap == null)
                throw new ArgumentNullException("character");

            if (character.IsBitmapUploaded)
                throw new InvalidOperationException($"The character '{character.Character}' upload has been requested while its current glyph is valid.");

            var targetSize = new Int2(character.Bitmap.Width, character.Bitmap.Rows);
            if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
            {
                // not enough space to place the new character -> remove less used characters and try again
                RemoveLessUsedCharacters();
                if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                {
                    // memory is too fragmented in order to place the new character -> clear all the characters and restart.
                    // TODO: This is invalid, we might delete character from current frame!
                    ClearCache();
                    if (!packer.Insert(targetSize.X, targetSize.Y, ref character.Glyph.Subrect))
                        throw new InvalidOperationException("The rendered character is too big for the cache texture");
                }
            }
            // Upload the bitmap to the atlas texture, with a 1px transparent border extending
            // beyond the allocated region to clear any stale pixels from previously freed glyphs.
            // This overlaps into neighbors' transparent borders (which are also zeroed), so no

View on GitHub (pinned to 96fad776d2)