# How raise-argument-error call gather more stacktrace?

**URL:** <https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795>\
**Category:** Questions & Answers\
**Created:** [March 12, 2023, 5:44am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795 "2023-03-12T05:44:27Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 12, 2023, 5:44am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/1 "2023-03-12T05:44:27Z")

</div>

I try to make may own version of raise-argument-error:

```scheme
(define (raise-argument-error* a b c)
  (raise
    (exn:fail:contract
      (format "~a: contract violation\n expected: ~a\n given: ~a" a b c)
      (current-continuation-marks)))
  (void))

(define (test1 x)
  (when (> x 0)
    (raise-argument-error 'test1 "<= 0" x))
  (+ x 1))

(define (test2 x)
  (when (> x 0)
    (raise-argument-error* 'test2 "<= 0" x))
  (+ x 1))

```

Then, a call `(test1 2)` shows in stracktrace:

```scheme
test-raise.rkt:12:4 
      (raise-argument-error 'test1 "<= 0" x))

test-raise.rkt:11:2 
    (when (> x 0)
    (raise-argument-error 'test1 "<= 0" x))

interactions from an unsaved editor:6:2 
  > (test1 2)

```

But `(test2 2)` gives :

```scheme
test-raise.rkt:7:6 
        (current-continuation-marks)))

test-raise.rkt:5:4 
      (exn:fail:contract
      (format "~a: contract violation\n expected: ~a\n given: ~a" a b c)
      (current-continuation-marks)))

test-raise.rkt:4:2 
    (raise
    (exn:fail:contract
      (format "~a: contract violation\n expected: ~a\n given: ~a" a b c)
      (current-continuation-marks)))

test-raise.rkt:17:4 
      (raise-argument-error* 'test2 "<= 0" x))

interactions from an unsaved editor:10:2 
  > (test2 2)

```

Is it possible to add frame

```scheme
    (when (> x 0)
    (raise-argument-error* 'test2 "<= 0" x))

```

like it is with raise-argument-error version?

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [March 12, 2023, 8:03am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/2 "2023-03-12T08:03:55Z")

</div>

Here’s a CP0’ed `when` expression in `test1`:

```scheme
(#2%$call-setting-continuation-attachment
                           (#2%cons
                             errortrace-key3.2384
                             '((when (> x 0)
                                 (raise-argument-error 'test1 "<= 0" x))
                                #[path.rkt-io.sls-path-0 #vu8(47 85 115 101 114 115 47 115 111 114 97 119 101 101 47 112 108 97 121 103 114 111 117 110 100 47 97 97 46 114 107 116) unix]
                                6 2 55 57))
                           (lambda ()
                             (if (#2%$call-setting-continuation-attachment
                                   (#2%cons
                                     errortrace-key3.2384
                                     '((> x 0)
                                        #[path.rkt-io.sls-path-0 #vu8(47 85 115 101 114 115 47 115 111 114 97 119 101 101 47 112 108 97 121 103 114 111 117 110 100 47 97 97 46 114 107 116) unix]
                                        6 8 61 7))
                                   (lambda () (#2%> x_1.2387 0)))
                                 WHEN-BODY
                                 (#2%void))
                             (#2%void)))

```

And here’s a CP0’ed `when` expression in `test2`:

```scheme
(#2%$call-setting-continuation-attachment
                           (#2%cons
                             errortrace-key3.2384
                             '((when (> x 0)
                                 (raise-argument-error* 'test1 "<= 0" x))
                                #[path.rkt-io.sls-path-0 #vu8(47 85 115 101 114 115 47 115 111 114 97 119 101 101 47 112 108 97 121 103 114 111 117 110 100 47 97 97 46 114 107 116) unix]
                                6 2 55 58))
                           (lambda ()
                             (if (#2%$call-setting-continuation-attachment
                                   (#2%cons
                                     errortrace-key3.2384
                                     '((> x 0)
                                        #[path.rkt-io.sls-path-0 #vu8(47 85 115 101 114 115 47 115 111 114 97 119 101 101 47 112 108 97 121 103 114 111 117 110 100 47 97 97 46 114 107 116) unix]
                                        6 8 61 7))
                                   (lambda () (#2%> x_1.2388 0)))
                                 WHEN-BODY
                                 (#2%void))))

```

where `WHEN-BODY` is a large expression that is mostly identical in both variants (except one major difference).

We can see that there’s an extra `(#2%void)` in the first variant, which makes the `if` expression no longer in the tail call position, leading to an extra frame. On the other hand, in the second variant, there is no extra `(#2%void)`, so the `if` expression is in the tail call position, meaning the frame information inside will override the frame information about `(when (> x 0) (raise-argument-error 'test1 "<= 0" x))`.

I believe the difference is mostly in how the call of `raise-argument-error` is compiled to:

```scheme
($app/no-return
                                           (#3%$top-level-value
                                             'raise-argument-error/user.rkt-rumble.sls-raise-argument-error/user-0)
                                           'test1
                                           "<= 0"
                                           x_1.2387)

```

In contrast, the call to `raise-argument-error*` is compiled to:

```scheme
($app/value
                                           1/raise-argument-error*4.2385
                                           'test1
                                           "<= 0"
                                           x_1.2388)

```

and these are optimized differently by the compiler. One leads to an extra `(#2%void)`.

My understanding is that `$app/no-return` and `$app/value` are things that are marked by the core compiler (i.e., the compiler knows what `raise-argument-error` does, so it specially treats the call differently). There’s not really a way you can influence it.

It is indeed surprising though that an optimization on `$app/no-return` doesn't preserve the tail call position.

@mflatt and @gus-massa would be able to tell if this is intentional.

---

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 12, 2023, 11:58am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/3 "2023-03-12T11:58:58Z")

</div>

I think, that it is intended. Otherwise in (define (f x) (if ... (do-something) (raise ...))) frame with (f x) would be lost (raise in tail position).

So, is it possible to make something by means of Racket? Or this behaviour is allowed only for builtins?

And, is it possible to send stack to the exception without last call to (current-continuation-marks)? I see, that `abs` shows only frame, where abs is called. But `raise-blame-error` also somehow omit it's inners in the continuation-marks...

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [March 12, 2023, 5:09pm UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/4 "2023-03-12T17:09:09Z")

</div>

Given what @sorawee discovered, if you grab the stackframe in the caller then it won't be overwritten:

```plaintext
(define (raise-argument-error* stk a b c)
  (raise
   (exn:fail:contract
    (format "~a: contract violation\n expected: ~a\n given: ~a" a b c)
    stk))
  (void))

(define (test3 x)
  (when (> x 0)
    (raise-argument-error* (current-continuation-marks) 'test3 "<= 0" x))
  (+ x 1))

```

This can be partially (though not perfectly) hidden from the caller:

```plaintext
(require syntax/parse/define)
(define-syntax-parse-rule (raise-argument-error*/stk . args)
  (raise-argument-error* (current-continuation-marks) . args))

(define (test4 x)
  (when (> x 0)
    (raise-argument-error*/stk 'test4 "<= 0" x))
  (+ x 1))

```

However, `raise-argument-error*/stk` doesn't work when used in conjunction with `apply` or other higher-order functions.

---

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 13, 2023, 2:36am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/5 "2023-03-13T02:36:19Z")

</div>

I see. But this way is not uniform with builtins.

Is the only way to make new correct exception to inject it into racket/error.ss?

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [March 13, 2023, 2:49am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/6 "2023-03-13T02:49:03Z")

</div>

No, I think the original `raise-argument-error*` is the way to go. The debug information injected by errortrace like what you see in `when` should not be relied upon.

Call stacks in the sense of [`continuation-mark-set->context	`](https://docs.racket-lang.org/reference/contmarks.html#%28def._%28%28quote._~23~25kernel%29._continuation-mark-set-~3econtext%29%29) (or the `context...` information in the error message) with possibly tail-call overwriting frames are to be expected.

---

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 13, 2023, 3:09am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/7 "2023-03-13T03:09:37Z")

</div>

DrRacket emits wrong messages for such exceptions.

```scheme
> (require cldr/dates-modern)
> (ca-generic "ff")
. . AppData\Roaming\Racket\8.8\pkgs\cldr-core\cldr\core.rkt:40:10: locale "ff" is not in package: cldr-dates-modern

```

It should point to the place of the error: ..AppData\Roaming\Racket\8.8\pkgs\cldr-dates-modern\cldr\dates-modern.rkt:27:6

So any use of the original `raise-argument-error*` will print the line of raise-argument-error\*'s definition instead of the line, where it is called. I'm sure, that it is wrong.

Maybe it is somehow possible to edit the continuation mark set context before savimg it to the exception struct?

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [March 13, 2023, 3:16am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/8 "2023-03-13T03:16:53Z")

</div>

For a normal _package_ setup, the package code is precompiled and thus those package code doesn't have debug (i.e. errortrace) information. When running code from DrRacket, the exception will point to user code because only use code has debug information.

---

<div class="post-metadata">

**Author:** ![sorawee](https://avatars.discourse-cdn.com/v4/letter/s/ea5d25/32.png) [@sorawee](https://racket.discourse.group/u/sorawee)\
**Post date:** [March 13, 2023, 3:27am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/9 "2023-03-13T03:27:59Z")

</div>

If you really want errortrace to operate on installed packages, you may consider using [https://docs.racket-lang.org/errortrace-pkg/](https://docs.racket-lang.org/errortrace-pkg/)

---

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 13, 2023, 3:51am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/10 "2023-03-13T03:51:26Z")

</div>

> For a normal _package_ setup

How to do this? I installed `cldr-dates-modern` via DrRacket File / Install package.  
How to make it precompiled?

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [March 13, 2023, 3:53am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/11 "2023-03-13T03:53:00Z")

</div>

Installing a package automatically compiles everything in it. If you have modified the files of the package, run `raco setup` or `raco setup --pkgs PACKAGE` again.

---

<div class="post-metadata">

**Author:** ![Kalimehtar](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/kalimehtar/32/394_2.png) [@Kalimehtar](https://racket.discourse.group/u/Kalimehtar)\
**Post date:** [March 13, 2023, 3:59am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/12 "2023-03-13T03:59:07Z")

</div>

Thank you! DrRacket makes additional stackframes if I open source to look at.

---

<div class="post-metadata">

**Author:** ![shhyou](https://avatars.discourse-cdn.com/v4/letter/s/ccd318/32.png) [@shhyou](https://racket.discourse.group/u/shhyou)\
**Post date:** [March 13, 2023, 4:03am UTC](https://racket.discourse.group/t/how-raise-argument-error-call-gather-more-stacktrace/1795/13 "2023-03-13T04:03:16Z")

</div>

To remove debug information created by DrRacket, you also need delete everything in `**/compiled/drracket/errortrace`
