New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Building a specific target can cause bad state #2904

spikefoo opened this Issue Jan 8, 2017 · 7 comments


None yet
4 participants

spikefoo commented Jan 8, 2017

(Using stack-1.3.2 on Arch Linux)

Steps to reproduce

Clone this sample project with two libraries: LibA, and LibB which depends on LibA.

$ ls
lib-a lib-b stack.yaml

Build with stack build, and run with stack exec lib-a-exe and stack exec lib-b-exe.

Next, change a function (named value) in LibA, and rebuild LibA only using stack build lib-a. Now lib-a-exe uses the updated function, but lib-b-exe still uses the old one, as expected.

Now try to rebuild LibB with stack build lib-b or stack build.


stack should update (relink?) LibB to use the new version of LibA.


stack never rebuilds LibB, causing it to forever use the old LibA.

This was suprising for me, because I thought stack build lib-a && stack build lib-b was equivalent to stack build. Instead, I found out it can result in a bad state where LibB is never rebuilt, forcing me to use one of these workarounds:


After making a change in LibA and running stack build lib-a, either:

  • Change a source file in LibB, forcing a rebuild. Or:
  • Remove lib-b/.stack-work.

Alternatively, never build a specific target (e.g. stack build lib-a) in the first place. Always run stack build to build all targets.


This comment has been minimized.


lwm commented Jan 20, 2017

I believe this use case was covered with stack build --force-dirty ?

  --[no-]force-dirty       Enable/disable Force treating all local packages as
                           having dirty files (useful for cases where stack
                           can't detect a file change

This comment has been minimized.


spikefoo commented Jan 23, 2017

It looks like stack build --force-dirty is a nicer alternative to the workaround of manually removing .stack-work.

But the issue still exists: stack build fails to rebuild a package after a dependency is updated and built using stack build $DEPENDENCY.

@mgsloan mgsloan added this to the P1: Must milestone Feb 1, 2017


This comment has been minimized.


mgsloan commented Feb 1, 2017

I can indeed reproduce this, and I agree that it's a bug. Marking it as a P1 issue since it violates consistency that ought to be there.


This comment has been minimized.


snoyberg commented Mar 7, 2017

This reminds me of haskell/cabal#2830. And in fact I'm seeing something very similar. When I do the initial stack build, I end up with the following package IDs:

id: lib-a-
key: lib-a-
id: lib-b-
key: lib-b-

If I modified the LibA.hs file and rebuild, I get exactly the same id and key. This is the cause of the problem here. When you run stack build lib-a, Stack unregisters lib-a, rebuilds it, and registers it. When you run stack build lib-b, the package looks valid, because its dependency (lib-a) is still present in the database with the same ID.

This is really a Cabal or GHC bug (it should generate unique package IDs if the package contents change). A simple workaround would be to aggressively unregister all users of a package when unregistering the dependency.

snoyberg added a commit that referenced this issue Mar 7, 2017

snoyberg added a commit that referenced this issue Mar 7, 2017

Switch unregister reason from Maybe Text to Text
The previous commit (fixing #2904) made the Maybe layer confusing and
error-prone. It was too easy to end up accidentally skipping an
unregister based on the two levels of Maybe wrapping. This simplifies
the codebase, without any change in behavior.

It would be even nicer to be able to prove statically that we always
generate a dirty reason.

@snoyberg snoyberg referenced this issue Mar 7, 2017


Aggressive unregister for #2904 #3047

2 of 2 tasks complete

This comment has been minimized.


snoyberg commented Mar 7, 2017

Please see #3047, which should fix this.


This comment has been minimized.


snoyberg commented Mar 7, 2017

It looks like Cabal is using the package key as the package id as well. The key depends only on the dependencies of the build, not the output, which would explain this bug. I'll try to repro against latest cabal and report upstream.

snoyberg added a commit that referenced this issue Mar 8, 2017


This comment has been minimized.


snoyberg commented Mar 8, 2017

Fixed by #3047. Cabal is saying what I thought they would: the meaning of package IDs has changed. I'm not too happy with that, but as usual we have no control over such things.

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