Skip to content

Cannot copy variable value when it's bigger than a certain length #5778

Closed

Description

@artdedeco

Describe the bug
When debugging, if I have a local variable of String type in the Variables window and its value is bigger than a certain length, the debugger will show it truncated with ellipsis and hitting Ctrl + C or right-clicking > Copy Value will only copy the shown value (truncated).

There's currently no alternative that I know of:

Using the debug console won't work for accessing private fields of other classes (and maybe would show the value truncated anway? Not sure)
Hovering over the variable in the editor also shows the value truncated;
There's no configuration option in launch.json for type:dart that I know of that controls this (apparently some other languages has an option for configuring this).

To Reproduce
Steps to reproduce the behavior:

  1. Create a String local with a big length (eg > 1500 characters)
  2. Start debugging (type: dart, request: launch)
  3. Use the Variables window to inspect your variable

Expected behavior
I can copy the full value

Screenshots

Image

Please complete the following information:

You can run the Dart: Collect Diagnostic Information command from the VS Code command palette (F1) to easily capture this information or provide it manually.

  • Operating System and version: Windows 11 Pro 25H2
  • VS Code version: win 1.105.1
  • Dart extension version: 3.122.0
  • Dart/Flutter SDK version: 3.8.0/3.32.0
  • Target device (if the issue relates to Flutter debugging): Windows

Activity

  1. FMorschel commented on Oct 31, 2025

    @FMorschel
    Contributor

    As a workaround while the maintained doesn't answer, when debugging, you can write the variable/expression on the debug console (there is a field below it for you to write things).

    When you press enter/return it should display the whole variable in the console for you. I don't believe the console has a limit on length for this but maybe is something you can try to see if it helps.

  2. artdedeco commented on Oct 31, 2025

    @artdedeco
    Author

    @FMorschel thanks for the suggestion, but I addressed that in the OP:

    Using the debug console won't work for accessing private fields of other classes (and maybe would show the value truncated anway? Not sure)

  3. FMorschel commented on Oct 31, 2025

    @FMorschel
    Contributor

    It should work just fine if you are within that file that defines it. Maybe try adding a breakpoint inside it to test. I should've been clearer, sorry.

  4. DanTup commented on Oct 31, 2025

    @DanTup
    Member

    I'm not able to reproduce this - while the value is truncated in the tooltip (which is expected), "Copy Value" does copy the full value in my tests. For example in the code:

    void main() {
      var a = A();
      print(a.a); // Breakpoint here
    }
    
    class A {
      var a = '1234567890' * 100;
    }
    

    And copying here:

    Image

    I get this in my clipboard:

    1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
    

    @andre-ss6 are you able to provide a small code sample that definitely triggers this issue for you that I could test with?

    This has been an issue in the past and I looked up the fix to see if it might be more recent than your SDK, but it was quite a while ago back in 2023:

    dart-lang/sdk@5929460

    Thanks!

  5. added
    awaiting infoRequires more information from the customer to progress
    on Oct 31, 2025
  6. artdedeco commented on Oct 31, 2025

    @artdedeco
    Author

    @DanTup

    Hey, sure. You're correct that it not always reproduces. More info below.

    First, here's the minimal repro:

    dart create dartdebugstringlengthbug

    dartdebugstringlengthbug.dart

    import 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart';
    
    final foo = Foo();
    
    void main(List<String> arguments) {
      print(foo.foo);
    }

    lib/dartdebugstringlengthbug.dart

    class Foo {
      final foo = "123" * 1000;
    }

    If you break on print, F10 to instantiate foo, go to Globals window, inspect foo and Copy Value the field, it'll copy truncated.

    Apparently there are few edge cases. I did some more tests after your reply:

    • The above code does not repro if you change final foo = Foo() to be a local or a field instead of a global.
    • The above code does repro if you change final foo = "123" * 1000; to be private, independently of whether final foo = Foo() is a local or global or a field in another class (sample code below)

    Also repros:

    dartdebugstringlengthbug.dart

    import 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart';
    
    void main(List<String> arguments) {
      Dartdebugstringlengthbug().test();
    }
    
    class Dartdebugstringlengthbug {
      final foo = Foo();
      void test() {
        print(foo.toString());
      }
    }

    lib/dartdebugstringlengthbug.dart

    class Foo {
      final _foo = "123" * 1000;
    }
  7. DanTup commented on Oct 31, 2025

    @DanTup
    Member

    @andre-ss6 perfect, thank you! I can repro at least some of these and will look into fixing.

  8. added
    in debuggingRelates to the debug adapter or process of running debug sessions
    and removed
    awaiting infoRequires more information from the customer to progress
    on Oct 31, 2025
  9. added this to the v3.124.0 milestone on Oct 31, 2025
  10. artdedeco commented on Oct 31, 2025

    @artdedeco
    Author

    @DanTup Thank you! Btw, I just noticed the conditions I specified may be more specific than necessary. If I've got my notes straight, the only thing you need is having a private field in a class that's in another file. Ignore this. The first repro I sent does not use private fields and still repros.

  11. DanTup commented on Oct 31, 2025

    @DanTup
    Member

    @andre-ss6 when I repro'd your first sample, I put it all in the same file too. I'll have to do some debugging to figure out exactly what's up, but my guess is that once fixed for one of your samples, it'll solve it for all of them. I'll post back once I get chance to look properly though. Thank you for the debugging and the test cases!

  12. added
    relies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available
    on Nov 4, 2025
  13. DanTup commented on Nov 4, 2025

    @DanTup
    Member

    I've a fix open at https://dart-review.googlesource.com/c/sdk/+/459560

    From my debugging, the issue affected child-variables of anything in "Globals", because we did not correctly pass down the expression to evaluate them (the way "Copy Value" and "Copy as Expression" work in VS Code is by re-evaluating a string expression to get the value).

    If you see a similar issue for anything that is not a child-variable of a Global, please let me know.

    The change is in the debug adapter which ships in the SDK, so after it's merged, it will take a Dart/Flutter SDK update to get the fix unfortunately (it won't show up in a Dart-Code update).

  14. artdedeco commented on Nov 4, 2025

    @artdedeco
    Author

    Thanks @DanTup.

    If you see a similar issue for anything that is not a child-variable of a Global, please let me know.

    I'm not sure of what technically constitutes a Global in the lang spec, but informally seems like there's no globals in my second sample here.

  15. DanTup commented on Nov 4, 2025

    @DanTup
    Member

    @andre-ss6 sorry, I should've been clearer. I meant inspecting things inside the "Globals" section in the "Variables" panel of the debug sidebar.

  16. artdedeco commented on Nov 4, 2025

    @artdedeco
    Author

    @andre-ss6 sorry, I should've been clearer. I meant inspecting things inside the "Globals" section in the "Variables" panel of the debug sidebar.

    Ah, sure. In that case, yes, that second sample repros using the Locals window as well.

  17. DanTup commented on Nov 5, 2025

    @DanTup
    Member

    @andre-ss6 can you confirm the precise steps for the second repro? I tried what I think you meant, but it seems to work there for me (I'm expanding this in Locals and accessing it there):

    Image
  18. artdedeco commented on Nov 5, 2025

    @artdedeco
    Author

    @DanTup That's weird. It's just the steps I provided (ie, that code + debug and break on line 10, try to copy the value from the Locals Window), and at least from the screenshot seems like exactly what you're doing. I tried removing each variable/difference from our tests -- I was testing on Windows, switched to Mac; changed package name to be different to the file and class names, like in your case -- still, all repro'd the bug.

    I'm attaching a screen recording as it may be easier to see what I'm doing/if we're doing anything differently:

    dart-issue.mov
  19. artdedeco commented on Nov 5, 2025

    @artdedeco
    Author

    Also here's a new recording showing how it doesn't repro when switching from _foo to foo (and I later switch back to _foo in the video to confirm that's the cause).

    dart-issue2.mov
  20. DanTup commented on Nov 5, 2025

    @DanTup
    Member

    @andre-ss6 is it possible you could capture a log for me?

    1. Start the app and get to the breakpoint
    2. Open the command palette (F1)
    3. Start the Dart: Capture Debugging Logs command
    4. Reproduce the issue where copying fails - please also try right-clicking on the item to see whether the "Copy as Expression" entry appears (as this should be tied to the same functionality as untruncating)
    5. Once you've copied, click Cancel on the logging notification to stop logging and open the log
    6. Provide the log here (be sure to repro in this small sample since the log will contain parts of your workspace code)

    (one thing to also check is whether Cmd+C and right-click -> Copy Value are doing different things?)

  21. artdedeco commented on Nov 5, 2025

    @artdedeco
    Author

    @DanTup Sure! I'm attaching the logs below.

    Reproduce the issue where copying fails - please also try right-clicking on the item to see whether the "Copy as Expression" entry appears (as this should be tied to the same functionality as untruncating)

    (one thing to also check is whether Cmd+C and right-click -> Copy Value are doing different things?)

    Copy expression does show up and cmd+c and right click both do the same thing. I show that in the first video (sorry for the a bit long recording, I know 😅 Less used to mac shortcuts + things always go wrong when recording 😅).

    Anyway, the log below does seem to have the answer as to what's going on! I just don't understand why it didn't repro for you though 🤔

    Log

    !! ⚠️ PLEASE REVIEW THIS LOG FOR SENSITIVE INFORMATION BEFORE SHARING ⚠️ !! Dart Code extension: 3.122.0 Flutter extension: 3.122.0 (not activated)

    App: Visual Studio Code
    App Host: desktop
    Version: mac 1.105.1

    Workspace type: Dart (LSP)
    Workspace name: dartdebugstringlengthbug

    Dart (3.9.2): /Users/andre/source/flutter/bin/cache/dart-sdk
    Flutter (3.35.7): /Users/andre/source/flutter (No device)

    Logging Categories:
    General, AnalyzerTiming, CommandProcesses, DartTest, DartToolingDaemon, DAP, VmService, DevTools, FlutterDaemon, FlutterRun, FlutterTest, FlutterWidgetPreview, WebDaemon

    Wed Nov 05 2025 [13:25:22 GMT-0300 (Brasilia Standard Time)] Log file started
    [1:25:22 PM] [DAP] [Info] ==> {"command":"updateSendLogsToClient","arguments":{"enabled":true},"type":"request","seq":17}
    [1:25:22 PM] [DAP] [Info] <== {"seq":29,"type":"response","command":"updateSendLogsToClient","request_seq":17,"success":true}
    [1:25:25 PM] [DAP] [Info] ==> {"command":"evaluate","arguments":{"expression":"this.foo._foo","frameId":1,"context":"clipboard","format":{"hex":false}},"type":"request","seq":18}
    [1:25:25 PM] [DAP] [Info] <== {"seq":30,"type":"event","body":{"message":"==> [VM] {"jsonrpc":"2.0","id":"32","method":"evaluateInFrame","params":{"isolateId":"isolates/8616239353089527","frameIndex":0,"expression":"this.foo._foo","disableBreakpoints":true,"idZoneId":"zones/1"}}"},"event":"dart.log"}
    [1:25:25 PM] [VmService] [Info] [Dart] ==> [VM] {"jsonrpc":"2.0","id":"32","method":"evaluateInFrame","params":{"isolateId":"isolates/8616239353089527","frameIndex":0,"expression":"this.foo._foo","disableBreakpoints":true,"idZoneId":"zones/1"}}
    [1:25:25 PM] [DAP] [Info] <== {"seq":31,"type":"event","body":{"message":"<== [VM] {"jsonrpc":"2.0","error":{"code":113,"message":"Expression compilation error","data":{"details":"org-dartlang-debug:synthetic_debug_expression:1:10: Error: The getter '_foo' isn't defined for the type 'Foo'.\n - 'Foo' is from 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart' ('lib/dartdebugstringlengthbug.dart').\nTry correcting the name to the name of an existing getter, or defining a getter or field named '_foo'.\nthis.foo._foo\n ^^^^","request":{"jsonrpc":"2.0","id":"32","method":"evaluateInFrame","params":{"isolateId":"isolates/8616239353089527","frameIndex":0,"expression":"this.foo._foo","disableBreakpoints":true,"idZoneId":"zones/1"}}}},"id":"32"}"},"event":"dart.log"}
    [1:25:25 PM] [DAP] [Info] <== {"seq":32,"type":"response","body":{"error":{"format":"{message}","id":1,"variables":{"message":"evaluateInFrame: (113) Expression compilation error\norg-dartlang-debug:synthetic_debug_expression:1:10: Error: The getter '_foo' isn't defined for the type 'Foo'.\n - 'Foo' is from 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart' ('lib/dartdebugstringlengthbug.dart').\nTry correcting the name to the name of an existing getter, or defining a getter or field named '_foo'.\nthis.foo._foo\n ^^^^","stack":"#0 DartDebugAdapter.evaluateRequest (package:dds/src/dap/adapters/dart.dart:1142:7)\n\n#1 BaseDebugAdapter.handle (package:dds/src/dap/base_debug_adapter.dart:141:7)\n\n"}}},"command":"evaluate","message":"evaluateInFrame: (113) Expression compilation error\norg-dartlang-debug:synthetic_debug_expression:1:10: Error: The getter '_foo' isn't defined for the type 'Foo'.\n - 'Foo' is from 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart' ('lib/dartdebugstringlengthbug.dart').\nTry correcting the name to the name of an existing getter, or defining a getter or field named '_foo'.\nthis.foo._foo\n ^^^^","request_seq":18,"success":false}
    [1:25:25 PM] [VmService] [Info] [Dart] <== [VM] {"jsonrpc":"2.0","error":{"code":113,"message":"Expression compilation error","data":{"details":"org-dartlang-debug:synthetic_debug_expression:1:10: Error: The getter '_foo' isn't defined for the type 'Foo'.\n - 'Foo' is from 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart' ('lib/dartdebugstringlengthbug.dart').\nTry correcting the name to the name of an existing getter, or defining a getter or field named '_foo'.\nthis.foo._foo\n ^^^^","request":{"jsonrpc":"2.0","id":"32","method":"evaluateInFrame","params":{"isolateId":"isolates/8616239353089527","frameIndex":0,"expression":"this.foo._foo","disableBreakpoints":true,"idZoneId":"zones/1"}}}},"id":"32"}
    Wed Nov 05 2025 [13:25:27 GMT-0300 (Brasilia Standard Time)] Log file ended

  22. DanTup commented on Nov 5, 2025

    @DanTup
    Member

    Thanks! This does indeed make sense now - it's failing to evaluate the private member from an expression, and therefore falling back to the truncated string it already had:

    org-dartlang-debug:synthetic_debug_expression:1:10: Error: The getter '_foo' isn't defined for the type 'Foo'.
     - 'Foo' is from 'package:dartdebugstringlengthbug/dartdebugstringlengthbug.dart' ('lib/dartdebugstringlengthbug.dart').
    Try correcting the name to the name of an existing getter, or defining a getter or field named '_foo'.
    this.foo._foo
     ^^^^
    

    There were some changes in the area of expression evaluation recently - I wonder if the new code supports evaluating the private field and old code did not - I will do some testing.

  23. DanTup commented on Nov 5, 2025

    @DanTup
    Member

    Yep, that's it - if I switch to the current stable then it fails like it does for you. On latest code, it works.

    I found this CL:

    dart-lang/sdk@1f845d1

    [CFE] Expression evaluation: Use dynamic get etc and fixup names to access private stuff when possible

    So there were two issues here:

    1. The globals issue - which will be fixed by https://dart-review.googlesource.com/c/sdk/+/459560
    2. Accessing privates - which was fixed by dart-lang/sdk@1f845d1

    Both will arrive in a future Dart/Flutter SDK release.

    There might still be cases where things don't work (because expression eval is always more restricted than just navigating across the types, but VS Code requires us to use an evaluated expression to copy the full version of a truncated value to the clipboard), we'll just have to file issues and look at them on a case-by-case basis to see whether they can be fixed.

    Thanks for your help tracking these two down!

  24. artdedeco commented on Nov 5, 2025

    @artdedeco
    Author

    Alrighty, sounds good. Thank you for following it up so quickly!

  25. DanTup commented on Nov 24, 2025

    @DanTup
    Member

    The fix for the remaining issue landed in dart-lang/sdk@4f1f82f

    The change is in the SDK, so will arrive in a future SDK release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    in debuggingRelates to the debug adapter or process of running debug sessionsis bugrelies on sdk changesSomething that requires changes in the Dart/Flutter SDK to ship before it will become available

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions