Skip to content

RenderProxyBoxMixin.computeDryBaseline throws when the child legitimately reports no baseline #189711

Closed

Description

@Yusufihsangorgel

Steps to reproduce

A RenderBox that has no baseline returns null from computeDryBaseline.
The documented contract explicitly allows this:

The implementation must return a value that represents the distance from the
top of the box to the first baseline of the box's contents, for the given
constraints, or null if the [RenderBox] has no baselines.

Wrap such a box in any proxy box and ask for a dry baseline:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

class NoBaseline extends SingleChildRenderObjectWidget {
  const NoBaseline({super.key});
  @override
  RenderObject createRenderObject(BuildContext context) => RenderNoBaseline();
}

class RenderNoBaseline extends RenderBox {
  @override
  void performLayout() => size = constraints.constrain(const Size(40, 20));
  @override
  Size computeDryLayout(BoxConstraints constraints) =>
      constraints.constrain(const Size(40, 20));
  @override
  double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) =>
      null; // documented: null means "no baselines"
}

void main() {
  testWidgets('proxy box over a child with no baseline', (tester) async {
    await tester.pumpWidget(MaterialApp(home: Scaffold(
      body: IntrinsicWidth(
        child: Text.rich(TextSpan(children: [
          WidgetSpan(
            alignment: PlaceholderAlignment.baseline,
            baseline: TextBaseline.alphabetic,
            child: Semantics(container: true, child: const NoBaseline()),
          ),
        ])),
      ),
    )));
    expect(tester.takeException(), isNull);
  });
}

Expected results

No exception. The child reported that it has no baseline, which is a valid
answer, so the proxy should report the same.

Actual results

The RenderSemanticsAnnotations class does not implement "computeDryBaseline".
  #2  RenderBox.computeDryBaseline (box.dart:2184)
  #3  RenderProxyBoxMixin.computeDryBaseline (proxy_box.dart:106)
  #4  RenderBox._computeDryBaseline (box.dart:2140)

Cause

RenderProxyBoxMixin.computeDryBaseline collapses two different cases into one
??:

double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
  final double? result = child?.getDryBaseline(constraints, baseline);
  return result ?? super.computeDryBaseline(constraints, baseline);
}

result is null both when there is no child and when the child answered "I
have no baseline". Only the first case should fall through to
super.computeDryBaseline, which exists to assert that the subclass did not
implement the method. In the second case the proxy throws even though
everything behaved correctly.

There is a second effect that makes this hard to trace. The throw happens
inside RenderBox._computeDryBaseline, after it has set
_computingThisDryBaseline and the library level renderBoxDoingDryBaseline.
The exception escapes past the cleanup, so if any caller catches it, those
flags stay set and every later RenderBox.size read in the same frame trips
'renderBoxDoingDryBaseline == null'. The reported failure then has no
dry baseline frames in its stack at all, because the dry pass has already
unwound. That is what Sub6Resources/flutter_html#1510 looks like from the
outside.

Proposed fix

@override
@protected
double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) {
  final RenderBox? child = this.child;
  return child == null
      ? super.computeDryBaseline(constraints, baseline)
      : child.getDryBaseline(constraints, baseline);
}

I verified this on 3.41.2:

  • the reproduction above passes
  • Sub6Resources/flutter_html#1510, which is the same bug reached through a
    real package, passes
  • reverting the change brings both failures back
  • flutter test test/rendering/ passes, 813 tests including the regression
    test below

Regression test, in the style of the existing file:

test('computeDryBaseline returns null when the child reports no baseline', () {
  final RenderBox child = RenderBoxWithoutBaseline();
  final RenderProxyBox parent = RenderProxyBox(child);
  const BoxConstraints constraints = BoxConstraints(maxWidth: 100, maxHeight: 100);
  layout(parent, constraints: constraints);

  // Returning null from computeDryBaseline is the documented way for a box to
  // say it has no baselines. The proxy must forward that, not treat it as an
  // unimplemented method.
  expect(parent.getDryBaseline(constraints, TextBaseline.alphabetic), isNull);
});

class RenderBoxWithoutBaseline extends RenderBox {
  @override
  void performLayout() => size = constraints.constrain(const Size(40, 20));

  @override
  Size computeDryLayout(BoxConstraints constraints) =>
      constraints.constrain(const Size(40, 20));

  @override
  double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) => null;
}

Without the fix that test fails with
The RenderProxyBox class does not implement "computeDryBaseline".

I have this ready as a PR against master if that is the preferred next step.

Flutter version

Reproduced on stable 3.41.2, macOS arm64, Dart 3.11.0. The checkout is at the
release commit itself:

$ git describe --tags --exact-match HEAD
3.41.2
$ git rev-parse --short HEAD
90673a4eef2   ("Bump engine version for 3.41.2 stable release (#182559)")

flutter doctor reports the channel as [user-branch] only because the local
clone's remote is not named origin; the framework source is the unmodified
3.41.2 stable tag.

Activity

  1. suryaKommana2662 commented on Jul 20, 2026

    @suryaKommana2662
    Contributor

    @Yusufihsangorgel Thanks for the report. I was able to reproduce this issue locally using the provided widget test.

    The initial failure matches the reported behavior:

    The RenderSemanticsAnnotations class does not implement "computeDryBaseline".
    

    The stack trace points to RenderProxyBoxMixin.computeDryBaseline, with the call sequence including:

    RenderBox.computeDryBaseline
    RenderProxyBoxMixin.computeDryBaseline
    RenderBox._computeDryBaseline
    

    After the initial rendering exception, I also observed additional layout and semantics assertions (such as RenderBox was not laid out and subsequent semantics-related assertions). Based on the provided reproduction and my local verification, the issue is reproducible. Routing this to team-framework for further investigation.

    Flutter Doctor Output

    [√] Flutter (Channel stable, 3.44.6, on Microsoft Windows [Version 10.0.26200.8875], locale en-IN) [343ms]
        • Flutter version 3.44.6 on channel stable at C:\flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision ee80f08bbf (11 days ago), 2026-07-08 15:02:06 -0700
        • Engine revision 83675ed276
        • Dart version 3.12.2
        • DevTools version 2.57.0
        • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios,
          cli-animations, enable-native-assets, enable-swift-package-manager, omit-legacy-version-file, enable-lldb-debugging,
          enable-uiscene-migration
    
    [√] Windows Version (Windows 11 or higher, 25H2, 2009) [1,048ms]
    
    [√] Android toolchain - develop for Android devices (Android SDK version 36.1.0) [3.0s]
        • Android SDK at C:\Android\Sdk
        • Emulator version 36.5.11.0 (build_id 15261927) (CL:N/A)
        • Platform android-36.1, build-tools 36.1.0
        • Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
          This is the JDK bundled with the latest Android Studio installation on this machine.
          To manually set the JDK path, use: `flutter config --jdk-dir="path/to/jdk"`.
        • Java version OpenJDK Runtime Environment (build 21.0.10+-14961533-b1163.108)
        • All Android licenses accepted.
    
    [√] Chrome - develop for the web [132ms]
        • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
    
    [√] Visual Studio - develop Windows apps (Visual Studio Community 2026 18.6.1) [131ms]
        • Visual Studio at C:\Program Files\Microsoft Visual Studio\18\Community
        • Visual Studio Community 2026 version 18.6.11819.183
        • Windows 10 SDK version 10.0.26100.0
    
    [√] Connected device (3 available) [398ms]
        • Windows (desktop) • windows • windows-x64    • Microsoft Windows [Version 10.0.26200.8875]
        • Chrome (web)      • chrome  • web-javascript • Google Chrome 150.0.7871.125
        • Edge (web)        • edge    • web-javascript • Microsoft Edge 150.0.4078.83
    
    [√] Network resources [672ms]
        • All expected network resources are available.
    
    • No issues found!
  2. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: renderingUI glitches reported at the engine/skia or impeller rendering level
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Jul 20, 2026
  3. Yusufihsangorgel commented on Jul 20, 2026

    @Yusufihsangorgel
    ContributorAuthor

    Thanks for confirming. Fix is up in #189723, with a regression test based on this reproduction.

  4. github-actions commented on Aug 13, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  5. locked as resolved and limited conversation to collaborators on Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

P1High-priority issues at the top of the work listc: renderingUI glitches reported at the engine/skia or impeller rendering levelframeworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework teamwaiting for PR to land (fixed)A fix is in flight

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions