<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jasper Blank</title>
    <description>The latest articles on DEV Community by Jasper Blank (@jasperblank).</description>
    <link>https://dev.to/jasperblank</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3871380%2Ff9b23bcf-549b-47f9-b55f-7bdbab6b577e.png</url>
      <title>DEV Community: Jasper Blank</title>
      <link>https://dev.to/jasperblank</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jasperblank"/>
    <language>en</language>
    <item>
      <title>One day with acados: 8 errors I hit and what they meant</title>
      <dc:creator>Jasper Blank</dc:creator>
      <pubDate>Fri, 10 Apr 2026 09:23:22 +0000</pubDate>
      <link>https://dev.to/jasperblank/one-day-with-acados-8-errors-i-hit-and-what-they-meant-2m48</link>
      <guid>https://dev.to/jasperblank/one-day-with-acados-8-errors-i-hit-and-what-they-meant-2m48</guid>
      <description>&lt;p&gt;Yesterday I spent a day learning &lt;code&gt;acados&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I was not trying to become an expert in nonlinear MPC in one sitting. I wanted to see where the friction actually was when going from "the examples run" to "I can change things and still understand what is happening."&lt;/p&gt;

&lt;p&gt;I used the Python examples, changed them, broke them on purpose, and kept notes. I also used Claude and Codex the whole time, but mostly as pair engineers: terminal output in, next step out, then back to the code.&lt;/p&gt;

&lt;p&gt;The main surprise was that the hardest part was usually not the control part. It was setup, code generation, environment state, and figuring out which changes were runtime-safe versus which changes forced regeneration.&lt;/p&gt;

&lt;p&gt;These were the eight most useful failures from that day.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;EOFError&lt;/code&gt; after "Tera template render executable not found"
&lt;/h2&gt;

&lt;p&gt;The first Python example did not just fail. It failed in a misleading way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tera template render executable not found ...
Do you wish to set up Tera renderer automatically?
...
EOFError: EOF when reading a line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last line points you toward Python input handling. The real problem was simpler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;t_renderer&lt;/code&gt; was missing&lt;/li&gt;
&lt;li&gt;the script tried to prompt for setup&lt;/li&gt;
&lt;li&gt;the shell was non-interactive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install &lt;code&gt;t_renderer&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one set the tone for the rest of the day. The raw error was not fake, but it was also not the useful diagnosis.&lt;br&gt;
Yesterday I spent a day learning &lt;code&gt;acados&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I was not trying to become an expert in nonlinear MPC in one sitting. I wanted to see where the friction actually was when going from "the examples run" to "I can change things and still understand what is happening."&lt;/p&gt;

&lt;p&gt;I used the Python examples, changed them, broke them on purpose, and kept notes. I also used Claude and Codex the whole time, but mostly as pair engineers: terminal output in, next step out, then back to the code.&lt;/p&gt;

&lt;p&gt;The main surprise was that the hardest part was usually not the control part. It was setup, code generation, environment state, and figuring out which changes were runtime-safe versus which changes forced regeneration.&lt;/p&gt;

&lt;p&gt;These were the eight most useful failures from that day.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. &lt;code&gt;EOFError&lt;/code&gt; after "Tera template render executable not found"
&lt;/h2&gt;

&lt;p&gt;The first Python example did not just fail. It failed in a misleading way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tera template render executable not found ...
Do you wish to set up Tera renderer automatically?
...
EOFError: EOF when reading a line
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last line points you toward Python input handling. The real problem was simpler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;t_renderer&lt;/code&gt; was missing&lt;/li&gt;
&lt;li&gt;the script tred to prompt for setup&lt;/li&gt;
&lt;li&gt;the shell was non-interactive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;install &lt;code&gt;t_renderer&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one set the tone for the rest of the day. The raw error was not fake, but it was also not the useful diagnosis.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Missing &lt;code&gt;.so&lt;/code&gt; really meant &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; was wrong
&lt;/h2&gt;

&lt;p&gt;Later I unset &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; and reran a working example. The failure was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OSError: libqpOASES_e.so: cannot open shared object file: No such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That points at one specific shared library. In practice the right action was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add &lt;code&gt;&amp;lt;acados_root&amp;gt;/lib&lt;/code&gt; back to &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a pattern I see a lot in technical tooling. The message is factually correct and still not the fastest route to a fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Copying a getting-started example was not enough
&lt;/h2&gt;

&lt;p&gt;I copied &lt;code&gt;minimal_example_closed_loop.py&lt;/code&gt; into my own folder so I could experiment on it without touching the original. It failed immediately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ModuleNotFoundError: No module named 'pendulum_model'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script looked standalone. It was not.&lt;/p&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;copy &lt;code&gt;pendulum_model.py&lt;/code&gt; and &lt;code&gt;utils.py&lt;/code&gt; too&lt;/li&gt;
&lt;li&gt;or keep running from the original example layout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is small, but it matters. It is exactly the kind of thing that makes a tool feel brittle when you are new to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. WSL clock skew looked worse than it was
&lt;/h2&gt;

&lt;p&gt;After changing &lt;code&gt;N_horizon&lt;/code&gt;, I ran the copied example from &lt;code&gt;/mnt/c&lt;/code&gt; and got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make: Warning: File 'Makefile' has modification time in the future
make: warning: Clock skew detected. Your build may be incomplete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance that looks like generated code might be corrupted. In my case it was mostly a filesystem issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;active build artifacts were on a Windows-mounted path&lt;/li&gt;
&lt;li&gt;build tools inside &lt;code&gt;WSL&lt;/code&gt; did not like the timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;keep active generated code on the Linux filesystem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is one of those cases where a good tool should say "probably environment noise" before the user goes hunting inside the OCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;yref&lt;/code&gt; shape errors were understandable, but late
&lt;/h2&gt;

&lt;p&gt;I injected a bad &lt;code&gt;yref&lt;/code&gt; shape and got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AcadosOcpSolver.set(): mismatching dimension for field "yref" with dimension 5 (you have 6)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This message was actually decent. The annoying part was somewhere else:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the example still did startup codegen/build first&lt;/li&gt;
&lt;li&gt;only after that did the local shape problem show up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case the fix was simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use the right path-stage &lt;code&gt;yref&lt;/code&gt; length&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So this is less "decoder magic" and more "tell me this earlier."&lt;/p&gt;

&lt;h2&gt;
  
  
  6. &lt;code&gt;W&lt;/code&gt; shape errors leaked internal details
&lt;/h2&gt;

&lt;p&gt;Then I broke the running cost matrix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AcadosOcpSolver.cost_set(): mismatching dimension for field "W" at stage c_int(0) with dimension (np.int32(5), np.int32(5)) (you have (6, 6))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the kind of output experienced users can parse and newer users still hate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it tells you the shape is wrong&lt;/li&gt;
&lt;li&gt;it also dumps internal type details into the message&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real takeaway was just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;expected &lt;code&gt;5x5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;got &lt;code&gt;6x6&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a good example of where normalization helps even if the solver is technically being precise.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. &lt;code&gt;status 4&lt;/code&gt; was not one thing
&lt;/h2&gt;

&lt;p&gt;One of the strongest cases came from contradictory bounds. The output looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;QP solver returned error status 3 (ACADOS_MINSTEP)
...
acados returned status 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the point where the stack stops being beginner-friendly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one layer is talking about the QP&lt;/li&gt;
&lt;li&gt;another layer is talking about the OCP solve&lt;/li&gt;
&lt;li&gt;the mapping between them is not obvious if you are still learning the tool&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case the real issue was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;contradictory bounds&lt;/li&gt;
&lt;li&gt;specifically &lt;code&gt;lbu &amp;gt; ubu&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the useful diagnosis was not just "status 4." It was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the QP failed&lt;/li&gt;
&lt;li&gt;start by checking feasibility of the bounds&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. &lt;code&gt;ACADOS_MAXITER&lt;/code&gt; meant different things in different contexts
&lt;/h2&gt;

&lt;p&gt;At first I had a clean example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;set &lt;code&gt;nlp_solver_max_iter&lt;/code&gt; very low&lt;/li&gt;
&lt;li&gt;get &lt;code&gt;status 2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That made &lt;code&gt;ACADOS_MAXITER&lt;/code&gt; look simple.&lt;/p&gt;

&lt;p&gt;Then I moved to a planar quadrotor MPC example and it stopped being simple.&lt;/p&gt;

&lt;p&gt;I found at least three versions of "status 2":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the iteration cap was genuinely too low&lt;/li&gt;
&lt;li&gt;I tightened runtime bounds and the maneuver became too hard&lt;/li&gt;
&lt;li&gt;a constrained maneuver failed on a short horizon, then succeeded when I lengthened the horizon&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The third case was the useful one.&lt;/p&gt;

&lt;p&gt;I had a tight active angle bound. A maneuver failed. The first guess was obvious:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the constraint is too tight&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I softened the constraint.&lt;br&gt;
Still failed.&lt;br&gt;
Slack stayed zero.&lt;/p&gt;

&lt;p&gt;Then I increased the horizon.&lt;br&gt;
The same maneuver succeeded.&lt;/p&gt;

&lt;p&gt;That changed how I think about debugging these failures. A useful tool should not flatten &lt;code&gt;status 2&lt;/code&gt; into one canned explanation. Sometimes the right next step is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;try a longer horizon before relaxing the constraint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is much closer to what an experienced user would actually do.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually found useful about Claude and Codex
&lt;/h2&gt;

&lt;p&gt;The part that worked was not "AI solves control engineering for you."&lt;/p&gt;

&lt;p&gt;What worked was much narrower:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paste exact terminal output&lt;/li&gt;
&lt;li&gt;ask for the next concrete step&lt;/li&gt;
&lt;li&gt;go run it&lt;/li&gt;
&lt;li&gt;write down what happened&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time something useful happened, I turned it into one of four things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an incident note&lt;/li&gt;
&lt;li&gt;an error/fix pair&lt;/li&gt;
&lt;li&gt;a recipe&lt;/li&gt;
&lt;li&gt;a regression test case&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That kept the whole day grounded in real failures instead of vague "can AI help with MPC?" discussion.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I had by the end of the day
&lt;/h2&gt;

&lt;p&gt;By the end of the sprint I had:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a small local acados decoder CLI&lt;/li&gt;
&lt;li&gt;a recipe layer for setup and runtime-vs-rebuild questions&lt;/li&gt;
&lt;li&gt;a semi-realistic trial pack of pasted logs&lt;/li&gt;
&lt;li&gt;a regression evaluator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More importantly, I had a better picture of the actual scope.&lt;/p&gt;

&lt;p&gt;The useful thing here is probably small:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;decode confusing acados errors&lt;/li&gt;
&lt;li&gt;suggest the next check&lt;/li&gt;
&lt;li&gt;explain a few common runtime-vs-rebuild boundaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is enough to be useful. It does not need to be a universal control assistant.&lt;/p&gt;

&lt;h2&gt;
  
  
  One external signal that mattered
&lt;/h2&gt;

&lt;p&gt;After I posted about this on the acados forum, one person replied to say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;yes, the segfault was real&lt;/li&gt;
&lt;li&gt;no, they never solved it&lt;/li&gt;
&lt;li&gt;they stopped using acados because of it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They did not have the old log anymore, so it was not a good eval case for the tool.&lt;/p&gt;

&lt;p&gt;But it was still useful. It showed that a confusing first failure can be enough to make someone leave the tool entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you use acados
&lt;/h2&gt;

&lt;p&gt;I would like to know whether the same pattern shows up for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup errors that surface as misleading Python failures&lt;/li&gt;
&lt;li&gt;status code combinations that are hard to interpret&lt;/li&gt;
&lt;li&gt;runtime-vs-rebuild confusion&lt;/li&gt;
&lt;li&gt;failures that look like infeasibility but turn out to be horizon or authority issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have an acados log that confused you, send it to me. Those are the cases I care about most right now.&lt;/p&gt;

</description>
      <category>controlsystems</category>
      <category>python</category>
      <category>debugging</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
