Skip to content

Value is sometimes not set when using DiffResults #269

Closed

Description

@gdalle

Here's an MWE I'm struggling to understand. My best guess sofar is that this is hitting a Julia compiler optimization which somehow eludes the value computation. Unless I'm just holding the thing wrong?

using ReverseDiff: ReverseDiff
using DiffResults: DiffResults

f(x) = sum(abs2, x)
x = [3.0, 5.0]
compiled_tape = ReverseDiff.compile(ReverseDiff.GradientTape(f, x))

function value_and_gradient1!(grad, tape, x)
    result = DiffResults.MutableDiffResult(zero(eltype(x)), (grad,))
    result = ReverseDiff.gradient!(result, tape, x)
    return DiffResults.value(result), DiffResults.gradient(result)
end

function value_and_gradient2!(grad, tape, x)
    result = DiffResults.MutableDiffResult(zero(eltype(x)), (grad,))
    result = ReverseDiff.gradient!(result, tape, x)
    return DiffResults.value(result), grad
end

function value_and_gradient_nested1!(grad, tape, x)
    y, _ = value_and_gradient1!(grad, tape, x)
    return y, grad
end

function value_and_gradient_nested2!(grad, tape, x)
    y, _ = value_and_gradient2!(grad, tape, x)
    return y, grad
end
julia> value_and_gradient1!(similar(x), compiled_tape, x)
(34.0, [6.0, 10.0])

julia> value_and_gradient_nested1!(similar(x), compiled_tape, x)  # wrong value
(0.0, [6.0, 10.0])

julia> value_and_gradient2!(similar(x), compiled_tape, x)
(34.0, [6.0, 10.0])

julia> value_and_gradient_nested2!(similar(x), compiled_tape, x)
(34.0, [6.0, 10.0])

Related:

Details
(jl_gKdWaj) pkg> st
Status `/private/var/folders/pt/myrxq2gs5hzcp79v5475_dh40000gp/T/jl_gKdWaj/Project.toml`
  [163ba53b] DiffResults v1.1.0
  [37e2e3b7] ReverseDiff v1.15.3

julia> versioninfo()
Julia Version 1.11.3
Commit d63adeda50d (2025-01-21 19:42 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin24.0.0)
  CPU: 11 × Apple M3 Pro
  WORD_SIZE: 64
  LLVM: libLLVM-16.0.6 (ORCJIT, apple-m2)
Threads: 5 default, 0 interactive, 2 GC (on 5 virtual cores)
Environment:
  JULIA_EDITOR = code

Activity

  1. nsajko commented on Feb 16, 2025

    @nsajko

    This doesn't reproduce on nightly Julia.

  2. nsajko commented on Feb 16, 2025

    @nsajko

    BTW, as mentioned on Slack, --compile=min is a good way to check if a bug is a miscompilation.

  3. gdalle commented on Feb 16, 2025

    @gdalle
    MemberAuthor

    You're right, with --compile=min it disappears as well. Not sure what to do about it then.

  4. nsajko commented on Feb 16, 2025

    @nsajko

    Not sure what to do about it then.

    Create a MWE and report an issue to JuliaLang/julia.

    Create the MWE by:

    1. starting from the reproducer above
    2. inlining the contents of the two packages and all dependencies
    3. delete irrelevant code manually
    4. optionally (I think it's slightly demanding to set up), use https://github.com/maleadt/creduce_julia to further reduce the MWE

    Another thing to do is bisect the fix (given that the bug is perhaps fixed on nightly), and see if it's backportable.

  5. gdalle commented on Feb 16, 2025

    @gdalle
    MemberAuthor

    Unfortunately I wouldn't even know where to begin to inline ReverseDiff. I tried removing it entirely and the effect disappeared.

  6. devmotion commented on Sep 16, 2026

    @devmotion
    Member

    This still reproduces, and it isn't a ReverseDiff bug — it's the Julia optimizer bug JuliaLang/julia#62812, fixed by #57201 in Julia 1.11.5 and never backported to the 1.10 LTS. Wrong on Julia 1.8 – 1.11.4, correct before and after, regardless of the ReverseDiff version. That's why it looked fixed on nightly in February.

    Two corrections to the original report: it hits a plain GradientTape too, not just a compiled one, and only the gradient path is affected — jacobian!, hessian! and gradient!(result, f, x) are fine. A package-free reproducer is in the upstream issue.

    Fix: no compiler barrier and no version check needed — just re-alias result the way the DiffResults docs ask for (#251), on the whole chain: src/api/gradients.jl and seeded_reverse_pass!(result, ::AbstractTape) in src/api/tape.jl. Still 0 allocations, still type stable.

    One note for #261: re-aliasing only helps if every level does it. On 1.10.12, #261 alone is still wrong, tape.jl alone is still wrong, both together are correct. #261 doesn't touch tape.jl, and since that method gets inlined, re-aliasing only in gradients.jl rebinds the same value and changes nothing — so #261 needs one more line to close this.

  7. added a commit that references this issue on Sep 17, 2026
    f79e366
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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions