#lobster workflow issue

1 messages · Page 1 of 1 (latest)

sick egret
#

I have the following lobster workflow, can you tell me how to run it manually because I think I have a typo in the invoke script https://cl1p.net/4564

grand pebbleBOT
#

To help others find answers, you can mark your question as solved via Right click solution message -> Apps -> âś… Mark Solution

untold solarBOT
fathom berryBOT
# sick egret I have the following lobster workflow, can you tell me how to run it manually be...

I checked the Lobster + /tools/invoke docs. I can’t see the actual workflow from cl1p here, so replace the path/args below with yours, but this is the manual shape.

First, sanity check version while debugging:

openclaw --version
openclaw status

If Lobster is enabled/allowed, run the workflow directly through the gateway:

export OPENCLAW_GATEWAY_TOKEN='your-token-here'

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
fathom berryBOT
fathom berryBOT
# sick egret I have the following lobster workflow, can you tell me how to run it manually be...
"pipeline": "some.command --json | another.command --stdin json"

If it pauses for approval, grab requiresApproval.resumeToken from the output and resume manually:

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "lobster",
    "action": "json",
    "args": {
      "action": "resume",
      "token": "PASTE_RESUME_TOKEN_HERE",
fathom berryBOT
sick egret
#

The actual issue is whether I am correctly naming the model here

args.provider = process.env.LLM_TASK_PROVIDER || "lmstudio";
args.model = process.env.LLM_TASK_MODEL || "lmstudio/qwen/qwen3.6-35b-a3b";
fathom berryBOT
# sick egret Try checking again here https://cl1p.net/4564

I can see it now. The workflow is:

sql_lead_drafts_email_output, with the suspect step here:

- id: draft_email
  command: sh -c 'node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js 2> /home/admin/.openclaw/workspace-dba-scout/debug-draft-email-stderr.txt'
  stdin: $debug_llm_request.stdout

To run the whole Lobster workflow manually through OpenClaw, save that YAML as a file, for example:

/home/admin/.openclaw/workspace-dba-scout/sql-leads-email.lobster

Then invoke Lobster via the gateway:

fathom berryBOT
# sick egret Try checking again here https://cl1p.net/4564
openclaw --version
export OPENCLAW_GATEWAY_TOKEN='your-token-here'

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "lobster",
    "action": "json",
    "args": {
      "action": "run",
      "pipeline": "/home/admin/.openclaw/workspace-dba-scout/sql-leads-email.lobster",
      "timeoutMs": 30000,
      "maxStdoutBytes": 512000
    }
fathom berryBOT
# sick egret Try checking again here https://cl1p.net/4564
  }' | jq

If you only want to debug the invoke-llm-task.js typo, run just the upstream input builder and that script:

cd /home/admin/.openclaw/workspace-dba-scout

python sql_leads/maintain_leads.py --dir sql_leads

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | node lobster-scripts/invoke-llm-task.js \
      > debug-draft-email.json \
fathom berryBOT
fathom berryBOT
fathom berryBOT
fathom berryBOT
# sick egret The actual issue is whether I am correctly naming the model here args.prov...
curl -sS http://127.0.0.1:1234/v1/models | jq '.data[].id'

Whatever that prints is the value that should go in args.model, while args.provider stays lmstudio.

Also make sure your OpenClaw config has the same model id under models.providers.lmstudio.models[].id, and if llm-task.config.allowedModels is set, it should contain the full canonical form, for example:

"allowedModels": ["lmstudio/qwen/qwen3.6-35b-a3b"]

Docs:
https://docs.openclaw.ai/tools/llm-task
https://docs.openclaw.ai/gateway/local-models

sick egret
#

I tried that but still doesn't work, how can I run it manually

fathom berryBOT
# sick egret I tried that but still doesn't work, how can I run it manually

Run it in layers so you can see exactly where it breaks.

First, get your version and confirm LM Studio’s actual model id:

openclaw --version
curl -sS http://127.0.0.1:1234/v1/models | jq '.data[].id'

Then test the model directly through LM Studio, using one of the ids printed above:

MODEL='qwen/qwen3.6-35b-a3b'

curl -sS http://127.0.0.1:1234/v1/chat/completions \
  -H 'Content-Type: application/json' \
fathom berryBOT
fathom berryBOT
# sick egret I tried that but still doesn't work, how can I run it manually
curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"tool\": \"llm-task\",
    \"action\": \"json\",
    \"args\": {
      \"provider\": \"lmstudio\",
      \"model\": \"$MODEL\",
      \"prompt\": \"Return a JSON object with ok true and source llm-task. No markdown.\",
      \"schema\": {
        \"type\": \"object\",
        \"properties\": {
          \"ok\": { \"type\": \"boolean\" },
          \"source\": { \"type\": \"string\" }
fathom berryBOT
# sick egret I tried that but still doesn't work, how can I run it manually
        },
        \"required\": [\"ok\", \"source\"],
        \"additionalProperties\": false
      },
      \"timeoutMs\": 60000
    }
  }" | jq

If that fails with 404, llm-task is not enabled/allowed. If it fails with “model not allowed”, your allowedModels needs the full key:

"allowedModels": ["lmstudio/qwen/qwen3.6-35b-a3b"]

If direct llm-task works, then run your workflow’s LLM part manually from the workspace:

fathom berryBOT
# sick egret I tried that but still doesn't work, how can I run it manually
cd /home/admin/.openclaw/workspace-dba-scout

python sql_leads/maintain_leads.py --dir sql_leads

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | LLM_TASK_PROVIDER=lmstudio \
    LLM_TASK_MODEL='qwen/qwen3.6-35b-a3b' \
    node lobster-scripts/invoke-llm-task.js \
      > debug-draft-email.json \
      2> debug-draft-email-stderr.txt

cat debug-draft-email-stderr.txt
jq . debug-draft-email.json
fathom berryBOT
sick egret
#

llm-task args: {
"provider": "lmstudio",
"model": "qwen/qwen3.6-35b-a3b",
"timeoutMs": 1800000,
"maxTokens": 32000,
"temperature": 0,
"requestTimeoutMs": 2100000
}
Gateway HTTP request failed
URL: http://127.0.0.1:18789/tools/invoke
Status: 401 Unauthorized
Raw response:
{"error":{"message":"Unauthorized","type":"unauthorized"}}

fathom berryBOT
# sick egret llm-task args: { "provider": "lmstudio", "model": "qwen/qwen3.6-35b-a3b", ...

That failure is before llm-task even runs. 401 Unauthorized from /tools/invoke means the Gateway rejected the bearer secret.

Check which auth mode your gateway is using:

openclaw --version
openclaw config get gateway.auth.mode
openclaw config get gateway.auth.token
openclaw config get gateway.auth.password

Do not paste the token/password here.

If mode is token, call it like:

fathom berryBOT
# sick egret llm-task args: { "provider": "lmstudio", "model": "qwen/qwen3.6-35b-a3b", ...
export OPENCLAW_GATEWAY_TOKEN='paste-token-from-config-here'

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "llm-task",
    "action": "json",
    "args": {
      "provider": "lmstudio",
      "model": "qwen/qwen3.6-35b-a3b",
      "prompt": "Return only {"ok":true}",
      "timeoutMs": 1800000,
      "maxTokens": 32000,
      "temperature": 0
fathom berryBOT
fathom berryBOT
sick egret
#

{
"error": {
"message": "Expected ',' or '}' after property value in JSON at position 162 (line 7 column 32)",
"type": "invalid_request_error"
}
}

fathom berryBOT
# sick egret { "error": { "message": "Expected ',' or '}' after property value in JSON ...

That one is my bad: the JSON body I gave had unescaped quotes inside the prompt string.

Use a heredoc so shell quoting doesn’t bite you:

export OPENCLAW_GATEWAY_TOKEN='paste-token-from-config-here'

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "llm-task",
  "action": "json",
  "args": {
    "provider": "lmstudio",
fathom berryBOT
fathom berryBOT
sick egret
#

That command just hangs

fathom berryBOT
# sick egret That command just hangs

If it hangs, don’t keep testing with timeoutMs: 1800000 and maxTokens: 32000 yet. That can make a local model sit there for a long time.

First prove the gateway endpoint returns quickly with a short client timeout:

export OPENCLAW_GATEWAY_TOKEN='paste-token-from-config-here'

curl --max-time 10 -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "llm-task",
  "action": "json",
  "args": {
    "provider": "lmstudio",
fathom berryBOT
# sick egret That command just hangs
    "model": "qwen/qwen3.6-35b-a3b",
    "prompt": "Return only {"ok":true}.",
    "timeoutMs": 10000,
    "maxTokens": 20,
    "temperature": 0
  }
}
JSON

If that times out too, check the gateway log in another terminal while running it:

openclaw logs --follow
fathom berryBOT
# sick egret That command just hangs

Also test LM Studio directly, bypassing OpenClaw:

MODEL='qwen/qwen3.6-35b-a3b'

curl --max-time 30 -sS http://127.0.0.1:1234/v1/chat/completions \
  -H 'Content-Type: application/json' \
  --data-binary @- <<JSON | jq
{
  "model": "$MODEL",
  "messages": [
    { "role": "user", "content": "Return only {\"ok\":true}." }
  ],
  "max_tokens": 20,
  "temperature": 0
}
fathom berryBOT
# sick egret That command just hangs
JSON

If the direct LM Studio call hangs, the issue is LM Studio/model loading/server capacity, not OpenClaw. If direct LM Studio works but llm-task hangs, paste the relevant openclaw logs --follow lines plus openclaw --version.

One more thing: if your heredoc command seems to hang immediately without network output, make sure the final JSON marker is at the start of the line with no spaces before it. Otherwise the shell is still waiting for the heredoc to finish.

sick egret
#

{
"error": {
"message": "Expected ',' or '}' after property value in JSON at position 150 (line 7 column 30)",
"type": "invalid_request_error"
}
}

fathom berryBOT
# sick egret { "error": { "message": "Expected ',' or '}' after property value in JSON ...

That parse error means the body reaching /tools/invoke is still invalid JSON, likely from the quotes in the prompt. Use a prompt with no embedded JSON-looking quotes:

export OPENCLAW_GATEWAY_TOKEN='paste-token-from-config-here'

curl --max-time 20 -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "llm-task",
  "action": "json",
  "args": {
    "provider": "lmstudio",
    "model": "qwen/qwen3.6-35b-a3b",
    "prompt": "Return one JSON object with a boolean field named ok set to true. No markdown.",
fathom berryBOT
fathom berryBOT
sick egret
#

{
"ok": false,
"error": {
"type": "tool_error",
"message": "tool execution failed"
}
}

fathom berryBOT
# sick egret { "ok": false, "error": { "type": "tool_error", "message": "tool exe...

Good, this means auth + JSON parsing are fixed. tool_error is the gateway’s sanitized wrapper; the real reason should be in the gateway logs.

Run this in one terminal:

openclaw logs --follow

Then rerun the short llm-task curl in another terminal. Look for lines around llm-task, tools-invoke, model, or provider.

Also run these and paste the non-secret output:

openclaw --version
openclaw config get plugins.entries.llm-task
openclaw config get models.providers.lmstudio
fathom berryBOT
# sick egret { "ok": false, "error": { "type": "tool_error", "message": "tool exe...
curl -sS http://127.0.0.1:1234/v1/models | jq '.data[].id'

Do not paste tokens/passwords.

The common causes at this point are:

  • llm-task is enabled but the model is not in allowedModels
  • models.providers.lmstudio.models[].id does not exactly match qwen/qwen3.6-35b-a3b
  • LM Studio direct API works, but OpenClaw’s provider config points at the wrong baseUrl or API mode
  • the local model returns non-JSON, so llm-task rejects it as invalid JSON

If you want one more isolating check, run LM Studio directly:

curl --max-time 30 -sS http://127.0.0.1:1234/v1/chat/completions \
fathom berryBOT
sick egret
#

I've changed it to this
curl --max-time 20 -sS http://127.0.0.1:18789/tools/invoke
-H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN"
-H "Content-Type: application/json"
--data-binary @- <<'JSON' | jq
{
"tool": "llm-task",
"action": "json",
"args": {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"prompt": "Return one JSON object with a boolean field named ok set to true. No markdown.",
"timeoutMs": 10000,
"maxTokens": 20,
"temperature": 0
}
}
JSON

and I can see model working but get this message

{
"ok": false,
"error": {
"type": "tool_error",
"message": "tool execution failed"
}
}

fathom berryBOT
# sick egret I've changed it to this curl --max-time 20 -sS http://127.0.0.1:18789/tools/invo...

I’d change that back unless LM Studio’s /v1/models literally prints lmstudio/qwen/qwen3.6-35b-a3b.

For llm-task, this:

"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b"

becomes the canonical key:

lmstudio/lmstudio/qwen/qwen3.6-35b-a3b

So it often causes allowedModels / provider-model lookup failures. The model field should match the raw LM Studio model id exactly:

fathom berryBOT
# sick egret I've changed it to this curl --max-time 20 -sS http://127.0.0.1:18789/tools/invo...
curl -sS http://127.0.0.1:1234/v1/models | jq -r '.data[].id'

Then use exactly that string as args.model.

The real reason for tool execution failed is still only in the gateway logs. Run this while retrying the curl:

openclaw logs --follow

If you want to avoid waiting on log noise, immediately after the failed request try:

openclaw logs --tail 100 | rg -i 'llm-task|tools-invoke|lmstudio|model not allowed|invalid json|provider/model|failed'
fathom berryBOT
# sick egret I've changed it to this curl --max-time 20 -sS http://127.0.0.1:18789/tools/invo...

My bet is one of these exact messages:

  • Model not allowed by llm-task plugin config: lmstudio/lmstudio/...
  • provider/model could not be resolved
  • LLM returned invalid JSON
  • a provider/runtime error from the LM Studio call

Also paste these non-secret outputs if you can:

openclaw config get plugins.entries.llm-task
openclaw config get models.providers.lmstudio
curl -sS http://127.0.0.1:1234/v1/models | jq -r '.data[].id'

Don’t paste the gateway token/password.

sick egret
#

No the model is working, I use lmstudio so I can see it processing

fathom berryBOT
# sick egret No the model is working, I use lmstudio so I can see it processing

Right, if LM Studio visibly starts processing, then OpenClaw is reaching the model. The failure is probably after the model call returns.

llm-task is strict: it tries to parse the model’s final text as JSON. If the model returns anything like <think>..., markdown, prose, or an empty/truncated response, llm-task throws and /tools/invoke only shows the generic tool execution failed.

Two things to try:

curl --max-time 60 -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "llm-task",
  "action": "json",
  "args": {
    "provider": "lmstudio",
fathom berryBOT
# sick egret No the model is working, I use lmstudio so I can see it processing
    "model": "lmstudio/qwen/qwen3.6-35b-a3b",
    "prompt": "Return exactly this JSON and nothing else: {"ok":true}. Do not include thinking, markdown, explanation, or any text before or after the JSON. /no_think",
    "timeoutMs": 60000,
    "maxTokens": 200,
    "temperature": 0
  }
}
JSON

And watch the real error while it runs:

openclaw logs --follow
fathom berryBOT
# sick egret No the model is working, I use lmstudio so I can see it processing

The log line matters here. If it says LLM returned invalid JSON, then the model is working but not returning clean JSON. For Qwen-style reasoning models, that often means it is emitting thinking text before the JSON; using /no_think, disabling reasoning in LM Studio, or switching to a non-reasoning/instruct variant usually fixes it.

If it says timeout/empty output/provider error, that points somewhere else. The sanitized tool_error alone doesn’t contain enough detail.

sick egret
#

{
"error": {
"message": "Expected ',' or '}' after property value in JSON at position 190 (line 7 column 61)",
"type": "invalid_request_error"
}
}

fathom berryBOT
# sick egret { "error": { "message": "Expected ',' or '}' after property value in JSON ...

That is still JSON syntax, not model behavior. The prompt string contains raw quotes around "ok", which makes the request body invalid.

Use this exact version with no embedded quotes in the prompt:

curl --max-time 60 -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "llm-task",
  "action": "json",
  "args": {
    "provider": "lmstudio",
    "model": "lmstudio/qwen/qwen3.6-35b-a3b",
    "prompt": "Return one JSON object with a boolean field named ok set to true. Do not include thinking, markdown, explanation, or any text before or after the JSON. /no_think",
fathom berryBOT
fathom berryBOT
sick egret
#

curl --max-time 60 -sS http://127.0.0.1:18789/tools/invoke
-H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN"
-H "Content-Type: application/json"
--data-binary @- <<'JSON' | jq
{
"tool": "llm-task",
"action": "json",
"args": {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"prompt": "Return one JSON object with a boolean field named ok set to true. Do not include thinking, markdown, explanation, or any text before or after the JSON. /no_think",
"timeoutMs": 60000,
"maxTokens": 200,
"temperature": 0
}
}
JSON

fathom berryBOT
# sick egret curl --max-time 60 -sS http://127.0.0.1:18789/tools/invoke \ -H "Authorization...

That JSON body is valid now. What output did that exact command return?

If it still returns:

{ "ok": false, "error": { "type": "tool_error", "message": "tool execution failed" } }

then the next step is definitely the gateway log. Run this in a second terminal before running the curl:

openclaw logs --follow | rg -i 'llm-task|tools-invoke|lmstudio|invalid json|empty output|model not allowed|provider/model|failed|error'

Then rerun the curl and paste the matching log lines.

Also, for one test, remove the duplicate provider from the model unless LM Studio’s /v1/models prints it exactly:

fathom berryBOT
sick egret
#

{
"ok": true,
"result": {
"content": [
{
"type": "text",
"text": "{\n "ok": true\n}"
}
],
"details": {
"json": {
"ok": true
},
"provider": "lmstudio",
"model": "qwen/qwen3.6-35b-a3b"
}
}

fathom berryBOT
# sick egret { "ok": true, "result": { "content": [ { "type": "text", ...

Nice, that proves llm-task works and the correct resolved model is:

provider: "lmstudio"
model: "qwen/qwen3.6-35b-a3b"

So in invoke-llm-task.js, use:

args.provider = process.env.LLM_TASK_PROVIDER || "lmstudio";
args.model = process.env.LLM_TASK_MODEL || "qwen/qwen3.6-35b-a3b";

Now debug the actual workflow step with the same known-good model values:

fathom berryBOT
# sick egret { "ok": true, "result": { "content": [ { "type": "text", ...
cd /home/admin/.openclaw/workspace-dba-scout

python sql_leads/maintain_leads.py --dir sql_leads

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | LLM_TASK_PROVIDER=lmstudio \
    LLM_TASK_MODEL='qwen/qwen3.6-35b-a3b' \
    node lobster-scripts/invoke-llm-task.js \
      > debug-draft-email.json \
      2> debug-draft-email-stderr.txt

cat debug-draft-email-stderr.txt
jq . debug-draft-email.json
fathom berryBOT
# sick egret { "ok": true, "result": { "content": [ { "type": "text", ...

If that fails, the problem is inside invoke-llm-task.js or the generated debug-llm-request.json, not the model name. The first thing I’d inspect is whether that script is adding bad JSON, using the wrong auth/token, or passing requestTimeoutMs instead of only the supported timeoutMs.

If this solves the thread, please right-click the solution message -> Apps -> âś… Mark Solution so Answer Overflow indexes it.

sick egret
#

ok, though I had to specify model as lmstudio/qwen/qwen3.6-35b-a3b to get it to work

fathom berryBOT
# sick egret ok, though I had to specify model as lmstudio/qwen/qwen3.6-35b-a3b to get it to ...

Got it, thanks for the correction. In that case your script should mirror the working curl value:

args.provider = process.env.LLM_TASK_PROVIDER || "lmstudio";
args.model = process.env.LLM_TASK_MODEL || "lmstudio/qwen/qwen3.6-35b-a3b";

Interesting bit: the successful response still reported the resolved model as qwen/qwen3.6-35b-a3b, so OpenClaw/LM Studio may be normalizing that on the way through. For your workflow, trust the exact value that made the direct llm-task call return ok: true.

Next step is just to run the workflow script with that env override:

LLM_TASK_PROVIDER=lmstudio \
LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js
fathom berryBOT
sick egret
#

That is working, however the lobster workflow still fails and I see this in the error logs

13:52:16
warn
diagnostic
lane wait exceeded: lane=main waitedMs=198946 queueAhead=1 activeAhead=1 activeNow=0 queueBehind=0
13:52:18
warn
agent/embedded
reasoning-only assistant turn detected: runId=llm-task-1779972537870 sessionId=llm-task-1779972537870 provider=lmstudio/qwen/qwen3.6-35b-a3b — retrying 1/2 with visible-answer continuation
13:52:19
warn
agent/embedded
reasoning-only assistant turn detected: runId=llm-task-1779972537870 sessionId=llm-task-1779972537870 provider=lmstudio/qwen/qwen3.6-35b-a3b — retrying 2/2 with visible-answer continuation
13:52:20
warn
agent/embedded
reasoning-only retries exhausted: runId=llm-task-1779972537870 sessionId=llm-task-1779972537870 provider=lmstudio/qwen/qwen3.6-35b-a3b attempts=2/2 — surfacing incomplete-turn error
13:52:20
warn
tools-invoke
tool execution failed: Error: LLM returned empty output
13:52:34
warn
agent/embedded
reasoning-only assistant turn detected: runId=llm-task-1779972753849 sessionId=llm-task-1779972753849 provider=lmstudio/qwen/qwen3.6-35b-a3b — retrying 1/2 with visible-answer continuation
13:52:35
warn
agent/embedded
reasoning-only assistant turn detected: runId=llm-task-1779972753849 sessionId=llm-task-1779972753849 provider=lmstudio/qwen/qwen3.6-35b-a3b — retrying 2/2 with visible-answer continuation
13:52:36
warn
agent/embedded
reasoning-only retries exhausted: runId=llm-task-1779972753849 sessionId=llm-task-1779972753849 provider=lmstudio/qwen/qwen3.6-35b-a3b attempts=2/2 — surfacing incomplete-turn error
13:52:36
warn
tools-invoke
tool execution failed: Error: LLM returned empty output

fathom berryBOT
# sick egret That is working, however the lobster workflow still fails and I see this in the ...

That log is the key. The model call is happening, but the embedded runner is receiving only a reasoning/thinking block and no visible assistant text:

reasoning-only assistant turn detected
...
LLM returned empty output

llm-task can only parse visible final text, so the workflow fails even though LM Studio is busy.

For this workflow, force the LLM task to disable thinking and keep the final answer tiny/visible. In your invoke-llm-task.js, add/ensure these fields before calling /tools/invoke:

args.provider = process.env.LLM_TASK_PROVIDER || "lmstudio";
args.model = process.env.LLM_TASK_MODEL || "lmstudio/qwen/qwen3.6-35b-a3b";
args.thinking = process.env.LLM_TASK_THINKING || "off";
fathom berryBOT
# sick egret That is working, however the lobster workflow still fails and I see this in the ...
args.temperature = 0;
args.timeoutMs = 1800000;
args.maxTokens = 32000;

And in the prompt that build-llm-request.js creates, add a hard final-output instruction near the end:

/no_think

Return ONLY the requested JSON as visible final text.
Do not include reasoning, analysis, markdown fences, or commentary.
The first character of your response must be { and the last character must be }.

Then test just the failing step:

fathom berryBOT
# sick egret That is working, however the lobster workflow still fails and I see this in the ...
cd /home/admin/.openclaw/workspace-dba-scout

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | LLM_TASK_PROVIDER=lmstudio \
    LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
    LLM_TASK_THINKING=off \
    node lobster-scripts/invoke-llm-task.js \
      > debug-draft-email.json \
      2> debug-draft-email-stderr.txt

If it still logs reasoning-only, disable reasoning/thinking for that model in LM Studio or try a non-reasoning instruct model for this JSON workflow. The lane wait exceeded line is secondary queue pressure; the actual failure is LLM returned empty output after reasoning-only retries.

sick egret
fathom berryBOT
# sick egret Full text can be found here https://cl1p.net/4564

I can see the issue in the pasted invoke-llm-task.js.

This line is working against you:

// JSON-only local model runs are usually more reliable without explicit thinking controls.
delete args.thinking;

Your logs show the opposite for this model/workflow: Qwen is producing a reasoning-only turn, then llm-task gets empty visible output.

Change that block to force thinking off:

args.provider = process.env.LLM_TASK_PROVIDER || "lmstudio";
args.model = process.env.LLM_TASK_MODEL || "lmstudio/qwen/qwen3.6-35b-a3b";
fathom berryBOT
# sick egret Full text can be found here https://cl1p.net/4564
args.maxTokens = 32000;
args.timeoutMs = Number(process.env.LLM_TASK_TIMEOUT_MS || args.timeoutMs || 600000);
args.temperature = Number(process.env.LLM_TASK_TEMPERATURE || 0);
args.thinking = process.env.LLM_TASK_THINKING || "off";

Also add the model-facing instruction to the prompt that build-llm-request.js creates, not just to the curl smoke test:

/no_think

Return ONLY the requested JSON as visible final text.
Do not include reasoning, analysis, markdown fences, or commentary.
The first character of your response must be { and the last character must be }.
fathom berryBOT
# sick egret Full text can be found here https://cl1p.net/4564

Then run the exact failing segment with the override:

cd /home/admin/.openclaw/workspace-dba-scout

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | LLM_TASK_PROVIDER=lmstudio \
    LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
    LLM_TASK_THINKING=off \
    node lobster-scripts/invoke-llm-task.js \
      > debug-draft-email.json \
      2> debug-draft-email-stderr.txt

If that still logs reasoning-only assistant turn detected, then LM Studio/model settings are overriding the request. In that case disable thinking/reasoning for this model in LM Studio or use a non-thinking instruct model for the JSON step.

fathom berryBOT
sick egret
#

I added that, but it is still not working and now no errors in the log

fathom berryBOT
# sick egret I added that, but it is still not working and now no errors in the log

If there are no gateway errors now, we need to stop treating it as an llm-task failure and find the exact failing Lobster step.

Run the pipeline one step at a time and check each debug file:

cd /home/admin/.openclaw/workspace-dba-scout

python sql_leads/maintain_leads.py --dir sql_leads

cat sql_leads/active.md \
  | node lobster-scripts/build-llm-request.js \
  | tee debug-llm-request.json \
  | LLM_TASK_PROVIDER=lmstudio \
    LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
    LLM_TASK_THINKING=off \
    node lobster-scripts/invoke-llm-task.js \
fathom berryBOT
# sick egret I added that, but it is still not working and now no errors in the log
      > debug-draft-email.json \
      2> debug-draft-email-stderr.txt

echo "invoke exit=$?"
wc -c debug-draft-email.json debug-draft-email-stderr.txt
cat debug-draft-email-stderr.txt
jq . debug-draft-email.json

If jq . debug-draft-email.json succeeds, continue:

node lobster-scripts/extract-llm-json.js \
  < debug-draft-email.json \
  | tee debug-extracted-json.json
fathom berryBOT
# sick egret I added that, but it is still not working and now no errors in the log

jq . debug-extracted-json.json

node lobster-scripts/render-email-html.js \
  < debug-extracted-json.json \
  | tee debug-rendered-email.json

jq . debug-rendered-email.json

node lobster-scripts/write-email-html-file.js \
  < debug-rendered-email.json

ls -lh sql-leads-draft-output.html

The first command that fails is the real current problem.

fathom berryBOT
# sick egret I added that, but it is still not working and now no errors in the log

Also add one stderr line after the gateway response parse in invoke-llm-task.js, right before process.stdout.write(text);:

console.error("llm-task response bytes:", Buffer.byteLength(text));

That tells us whether the script is receiving a response but the later parser/render step dislikes it, versus the request still hanging. Paste the first failing command’s stderr/stdout shape, not tokens.

sick egret
#

It just hangs after ouputing this from the maintenance
wc -c debug-draft-email.json debug-draft-email-stderr.txt
cat debug-draft-email-stderr.txt
jq . debug-draft-email.json
Lead file maintenance complete.
active_cutoff_date: 2026-05-21 (7 days)
archive_cutoff_date: 2026-03-29 (60 days)
active leads kept: 10
expired/moved from active: 30
processed/sent/rejected leads: 0
dedupe archive rows removed: 0
summary rows rebuilt: 10
oldest remaining active lead_date: 2026-05-21
verified: no remaining active lead is older than active_cutoff_date

fathom berryBOT
# sick egret It just hangs after ouputing this from the maintenance wc -c debug-draft-email.j...

That output means the maintenance step finished. The shell is hanging before it reaches wc -c ..., so it’s stuck in this part of the pipeline:

cat sql_leads/active.md |
node lobster-scripts/build-llm-request.js |
node lobster-scripts/invoke-llm-task.js

Split it into files so we can see which command is waiting:

cd /home/admin/.openclaw/workspace-dba-scout

python sql_leads/maintain_leads.py --dir sql_leads

timeout 30s node lobster-scripts/build-llm-request.js \
fathom berryBOT
fathom berryBOT
# sick egret It just hangs after ouputing this from the maintenance wc -c debug-draft-email.j...
  LLM_TASK_TIMEOUT_MS=60000 \
  INVOKE_HTTP_TIMEOUT_MS=90000 \
  node lobster-scripts/invoke-llm-task.js \
    < debug-llm-request.json \
    > debug-draft-email.json \
    2> debug-draft-email-stderr.txt

echo "invoke exit=$?"
wc -c debug-draft-email.json debug-draft-email-stderr.txt
cat debug-draft-email-stderr.txt
jq . debug-draft-email.json

While that second command is running, in another terminal:

fathom berryBOT
# sick egret It just hangs after ouputing this from the maintenance wc -c debug-draft-email.j...
tail -f debug-draft-email-stderr.txt
openclaw logs --follow | rg -i 'llm-task|tools-invoke|reasoning-only|empty output|failed|timeout|lmstudio'

My read: because invoke-llm-task.js redirects stderr into debug-draft-email-stderr.txt, you won’t see its “llm-task args” line until the process exits unless you tail the file. The split commands will tell us whether it’s hanging before the HTTP request, inside /tools/invoke, or waiting on LM Studio.

sick egret
#

The first step completes. The second step hangs and I am not seeing lmstudio processing

fathom berryBOT
# sick egret The first step completes. The second step hangs and I am not seeing lmstudio pro...

If step 2 hangs and LM Studio never starts processing, the request is probably not reaching the model. Two likely causes in your pasted script:

  1. invoke-llm-task.js is stuck before/inside the HTTP call.
  2. The explicit sessionKey: "agent:lead-scout:main" is putting the tool call onto a busy/blocked lane.

First, remove this line from the payload for debugging:

sessionKey: process.env.OPENCLAW_SESSION_KEY || "agent:lead-scout:main",

So the payload becomes:

const payload = {
  tool: "llm-task",
fathom berryBOT
fathom berryBOT
# sick egret The first step completes. The second step hangs and I am not seeing lmstudio pro...
console.error("gateway response bytes:", Buffer.byteLength(res.text || ""));

Run it again with a short hard timeout:

timeout 120s env \
  LLM_TASK_PROVIDER=lmstudio \
  LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
  LLM_TASK_THINKING=off \
  LLM_TASK_TIMEOUT_MS=60000 \
  INVOKE_HTTP_TIMEOUT_MS=90000 \
  node lobster-scripts/invoke-llm-task.js \
    < debug-llm-request.json \
    > debug-draft-email.json \
fathom berryBOT
# sick egret The first step completes. The second step hangs and I am not seeing lmstudio pro...
    2> debug-draft-email-stderr.txt

echo "invoke exit=$?"
cat debug-draft-email-stderr.txt

If you see posting to... but no gateway status..., it is waiting on /tools/invoke. In that case check the gateway queue/logs:

openclaw logs --tail 200 | rg -i 'lane wait|llm-task|tools-invoke|lead-scout|queue|timeout|failed'

The fact that direct curl worked but this script hangs points strongly at either the sessionKey difference or the generated debug-llm-request.json being much larger/slower than the smoke test. Removing sessionKey makes the script match the working curl much more closely.

sick egret
fathom berryBOT
# sick egret Can you give me the full script here https://cl1p.net/4565

I put the full script here: https://cl1p.net/4565

Main changes from your pasted version:

  • no hardcoded sessionKey; it only uses OPENCLAW_SESSION_KEY if you explicitly set it
  • keeps args.thinking = "off" by default
  • logs posting to, has bearer auth, gateway status, and response bytes
  • supports either OPENCLAW_GATEWAY_TOKEN or OPENCLAW_GATEWAY_PASSWORD

Run it like:

cd /home/admin/.openclaw/workspace-dba-scout

timeout 120s env \
  LLM_TASK_PROVIDER=lmstudio \
  LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
fathom berryBOT
# sick egret Can you give me the full script here https://cl1p.net/4565
  LLM_TASK_THINKING=off \
  LLM_TASK_TIMEOUT_MS=60000 \
  INVOKE_HTTP_TIMEOUT_MS=90000 \
  node lobster-scripts/invoke-llm-task.js \
    < debug-llm-request.json \
    > debug-draft-email.json \
    2> debug-draft-email-stderr.txt

cat debug-draft-email-stderr.txt

If it prints posting to... but never prints gateway status..., it’s waiting inside /tools/invoke. If it prints a gateway status, the next line tells us what came back.

sick egret
#

that worked

fathom berryBOT
# sick egret that worked

Good, that means the culprit was likely the hardcoded sessionKey routing the invoke into a blocked/busy lane, with the reasoning setting as a secondary fix.

For the Lobster workflow, keep the updated invoke-llm-task.js and rerun the full workflow. If it completes, please right-click the solution message -> Apps -> âś… Mark Solution so Answer Overflow indexes the fix for the next person.

sick egret
#

i rerun workflow. it failed and now that stderr file has this

llm-task args: {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"thinking": "low",
"timeoutMs": 600000,
"maxTokens": 8000,
"temperature": 0,
"requestTimeoutMs": 900000,
"sessionKey": null
}
posting to: http://127.0.0.1:18789/tools/invoke
has bearer auth: true
gateway status: 500 Internal Server Error
gateway response bytes: 76
Gateway HTTP request failed
URL: http://127.0.0.1:18789/tools/invoke
Status: 500 Internal Server Error
Raw response:
{"ok":false,"error":{"type":"tool_error","message":"tool execution failed"}}

fathom berryBOT
# sick egret i rerun workflow. it failed and now that stderr file has this llm-task args: { ...

The stderr shows the workflow is not using the same settings as the working manual test:

"thinking": "low"

That means debug-llm-request.json is carrying thinking: "low", and the script preserved it. For this model, that can trigger the reasoning-only/empty-output failure again.

Change these lines in invoke-llm-task.js so env/defaults override the generated request:

args.thinking = process.env.LLM_TASK_THINKING || "off";
args.maxTokens = Number(process.env.LLM_TASK_MAX_TOKENS || 32000);
args.timeoutMs = Number(process.env.LLM_TASK_TIMEOUT_MS || args.timeoutMs || 600000);
args.temperature = Number(process.env.LLM_TASK_TEMPERATURE || 0);
fathom berryBOT
# sick egret i rerun workflow. it failed and now that stderr file has this llm-task args: { ...

Important part: do not use args.thinking || "off" there, because the generated "low" will win.

Then rerun the workflow with an explicit env override if Lobster lets you pass env, or just rely on the script default after the edit:

LLM_TASK_THINKING=off LLM_TASK_MAX_TOKENS=32000 ...

Also check the gateway log for the 500’s real cause:

openclaw logs --tail 100 | rg -i 'llm-task|reasoning-only|empty output|invalid json|tool execution failed|lmstudio'

My bet is the log is back to reasoning-only or LLM returned empty output, because the workflow sent thinking: low while the manual passing test used off.

sick egret
#

I can see this in the log file
15:05:58
warn
tools-invoke
tool execution failed: Error: Thinking level "low" is not supported for lmstudio/qwen/qwen3.6-35b-a3b. Use one of: off.
15:05:58
error
[tools] lobster failed: workflow command failed (1): sh -c 'node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js 2> /home/admin/.openclaw/workspace-dba-scout/debug-draft-email-stderr.txt' raw_params={"action":"run","pipeline":"/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster","timeoutMs":1800000,"maxStdoutBytes":512000}
15:05:58
error
[tools] lobster failed: workflow command failed (1): sh -c 'node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js 2> /home/admin/.openclaw/workspace-dba-scout/debug-draft-email-stderr.txt' raw_params={"action":"run","pipeline":"/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster","timeoutMs":1800000,"maxStdoutBytes":512000}
15:06:07
warn
tools-invoke
tool execution failed: Error: Thinking level "low" is not supported for lmstudio/qwen/qwen3.6-35b-a3b. Use one of: off.

fathom berryBOT
# sick egret I can see this in the log file 15:05:58 warn tools-invoke tool execution failed...

Yep, that confirms it exactly: the generated request is still sending thinking: "low", and this model only supports off.

Patch invoke-llm-task.js so it overwrites the incoming value unconditionally:

args.thinking = process.env.LLM_TASK_THINKING || "off";

Not this:

args.thinking = process.env.LLM_TASK_THINKING || args.thinking || "off";

because args.thinking is currently "low".

You can verify before rerunning Lobster:

fathom berryBOT
fathom berryBOT
sick egret
#

I ran it it just hung again

fathom berryBOT
# sick egret I ran it it just hung again

Ok, then we need to distinguish “hung before gateway”, “hung inside gateway queue”, and “hung waiting for LM Studio”.

Run the invoke step with a hard outer timeout and then show stderr:

cd /home/admin/.openclaw/workspace-dba-scout

timeout 120s node lobster-scripts/invoke-llm-task.js \
  < debug-llm-request.json \
  > debug-draft-email.json \
  2> debug-draft-email-stderr.txt

echo "exit=$?"
cat debug-draft-email-stderr.txt
wc -c debug-draft-email.json
fathom berryBOT
# sick egret I ran it it just hung again

While it is running, also run:

openclaw logs --follow | rg -i 'llm-task|tools-invoke|lane wait|reasoning-only|empty output|thinking level|timeout|lmstudio|failed'

The stderr must show "thinking": "off". If it still says "thinking": "low", the script edit did not take effect.

If stderr shows posting to... but never gateway status..., the gateway call is stuck. Since the smoke test works, try shrinking the generated request to prove the large prompt/schema is the trigger:

cat > /tmp/llm-task-small.json <<'JSON'
{
  "provider": "lmstudio",
  "model": "lmstudio/qwen/qwen3.6-35b-a3b",
  "thinking": "off",
fathom berryBOT
# sick egret I ran it it just hung again
  "prompt": "Return one JSON object with a boolean field named ok set to true. No markdown.",
  "timeoutMs": 60000,
  "maxTokens": 200,
  "temperature": 0
}
JSON

timeout 120s node lobster-scripts/invoke-llm-task.js \
  < /tmp/llm-task-small.json \
  > /tmp/llm-task-small.out \
  2> /tmp/llm-task-small.err

cat /tmp/llm-task-small.err
jq . /tmp/llm-task-small.out
fathom berryBOT
# sick egret I ran it it just hung again

If the small JSON works but debug-llm-request.json hangs, the issue is the generated request size/content or output size, not auth/model routing anymore. Then check:

wc -c debug-llm-request.json
jq 'keys' debug-llm-request.json
jq '.prompt | length' debug-llm-request.json

Paste those non-secret outputs plus the stderr.

sick egret
#

I ran it again, nothing in the log files, jut this in the stderr file

#

llm-task args: {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"thinking": "off",
"timeoutMs": 600000,
"maxTokens": 8000,
"temperature": 0,
"requestTimeoutMs": 900000,
"sessionKey": null
}
posting to: http://127.0.0.1:18789/tools/invoke
has bearer auth: true

fathom berryBOT
fathom berryBOT
# sick egret I ran it again, nothing in the log files, jut this in the stderr file

Please run this exact check and paste the output:

cd /home/admin/.openclaw/workspace-dba-scout

timeout 30s node lobster-scripts/invoke-llm-task.js \
  < /tmp/llm-task-small.json \
  > /tmp/llm-task-small.out \
  2> /tmp/llm-task-small.err

echo "exit=$?"
cat /tmp/llm-task-small.err
wc -c /tmp/llm-task-small.out
jq . /tmp/llm-task-small.out

Also confirm this line in the stderr says off, not low:

fathom berryBOT
fathom berryBOT
# sick egret llm-task args: { "provider": "lmstudio", "model": "lmstudio/qwen/qwen3.6-35b...

That tells us the script is definitely stuck waiting for the HTTP response from /tools/invoke. It has not reached LM Studio, and it has not received a gateway status.

Two quick isolations:

  1. Test the same script with the tiny payload. If this works, the generated debug-llm-request.json is the trigger.
cat > /tmp/llm-task-small.json <<'JSON'
{
  "provider": "lmstudio",
  "model": "lmstudio/qwen/qwen3.6-35b-a3b",
  "thinking": "off",
  "prompt": "Return one JSON object with a boolean field named ok set to true. No markdown.",
  "timeoutMs": 60000,
  "maxTokens": 200,
  "temperature": 0
fathom berryBOT
fathom berryBOT
# sick egret llm-task args: { "provider": "lmstudio", "model": "lmstudio/qwen/qwen3.6-35b...
wc -c debug-llm-request.json
jq 'keys' debug-llm-request.json
jq '.prompt | length' debug-llm-request.json

Also add one more debug line before postJson(...) in the script:

console.error("payload bytes:", Buffer.byteLength(JSON.stringify(payload)));

If the tiny payload works but the full one hangs, reduce the generated prompt or schema. If the tiny payload also hangs through the script but your manual curl works, then the script/request path differs from the curl and we should compare the exact payload next.

sick egret
#

The small payload works, but a large payload works too. The issue is the if it is called from the lobster pipeline it just hangs and I don't see lmstudio processing anything

fathom berryBOT
# sick egret The small payload works, but a large payload works too. The issue is the if it i...

That nails it: the script works standalone, small and large payloads work standalone, but it hangs only when called from the Lobster pipeline and LM Studio never sees traffic.

That means the hang is almost certainly re-entrancy/queueing: embedded Lobster is already running as a Gateway tool, then a shell step inside that Lobster run calls back into the same Gateway /tools/invoke endpoint for llm-task. The nested request waits behind the workflow that is waiting for the nested request. Classic self-deadlock.

So the fix is architectural, not another model-name tweak. Pick one of these:

  1. Best for now: don’t call /tools/invoke from inside an embedded Lobster step. Replace invoke-llm-task.js with a script that calls LM Studio directly at http://127.0.0.1:1234/v1/chat/completions, then outputs the JSON shape your later steps expect.

  2. Or run Lobster outside the Gateway, using the standalone Lobster CLI. Then the workflow process is not occupying the Gateway tool lane, so its invoke-llm-task.js can call /tools/invoke normally.

  3. Or split the workflow: let Lobster run through debug_llm_request, stop; run invoke-llm-task.js manually/outside Lobster; then run the render/write steps.

For your current workflow, option 1 is the cleanest: keep Lobster deterministic and make the model step a normal local command instead of a nested OpenClaw tool call.

The evidence is:

  • direct invoke-llm-task.js < debug-llm-request.json works
  • inside Lobster it prints posting to: /tools/invoke
fathom berryBOT
sick egret
#

I want lobster to work as described

fathom berryBOT
# sick egret I want lobster to work as described

I agree. Based on the Lobster docs, openclaw.invoke / Gateway tool invocation from a Lobster workflow is intended to work. Your repro strongly suggests a bug in embedded Lobster/Gateway scheduling, not your LM Studio config anymore.

Please grab:

openclaw --version
openclaw config get plugins.entries.lobster
openclaw config get plugins.entries.llm-task

Then file this as a GitHub issue: https://github.com/openclaw/openclaw/issues

Useful issue summary:

Embedded Lobster workflow deadlocks/hangs when a workflow command calls /tools/invoke for llm-task.
fathom berryBOT
# sick egret I want lobster to work as described

What works:
- invoke-llm-task.js works standalone with the same debug-llm-request.json
- small and large payloads both work standalone
- LM Studio processes requests when run outside Lobster

What fails:
- same script called from an embedded Lobster workflow prints:
  posting to: http://127.0.0.1:18789/tools/invoke
  has bearer auth: true
  then hangs forever
- LM Studio never sees the request
- gateway logs show no llm-task/tool execution for the nested request

Expected:
fathom berryBOT
# sick egret I want lobster to work as described
- Lobster workflow can invoke OpenClaw tools as documented, or fails fast with a clear re-entrant invocation error.

Suspicion:
- /tools/invoke request is queued behind the currently-running Lobster tool call, while Lobster is waiting for that nested request to finish.

For now, the practical workaround is still to avoid calling /tools/invoke from inside the embedded Lobster run: call LM Studio directly in that workflow step, run standalone Lobster outside the Gateway, or split the workflow around the LLM step. But yes, as documented, this should not silently hang.

sick egret
#

It worked fine last week, clearly another openclaw upgrade broke it

fathom berryBOT
# sick egret It worked fine last week, clearly another openclaw upgrade broke it

That’s a fair read. Given it worked last week and now the same nested /tools/invoke call hangs before LM Studio sees anything, this does look like a regression in OpenClaw’s embedded Lobster/tool scheduling path.

For a useful bug report, capture:

openclaw --version
openclaw status --all
openclaw config get plugins.entries.lobster
openclaw config get plugins.entries.llm-task

If you know the last working version, include that too. The strongest repro sentence is:

Standalone invoke-llm-task.js works with the same input, but the same script hangs only when executed as a Lobster workflow step. It prints "posting to /tools/invoke" and "has bearer auth: true"; LM Studio never receives the request; gateway logs show no nested llm-task execution.
fathom berryBOT
sick egret
#

That is too vague I want a proper error log

fathom berryBOT
# sick egret That is too vague I want a proper error log

Fair. Here’s a proper capture recipe that will produce a useful error bundle instead of “it hangs”.

  1. Turn file logging up temporarily:
openclaw config set logging.level trace
openclaw gateway restart

If you don’t want trace, use debug, but for a scheduler/queue hang I’d use trace briefly.

  1. Run this capture from the workspace. It timestamps the repro, forces a 90s failure instead of an infinite hang, and saves stderr/stdout/log excerpts:
cd /home/admin/.openclaw/workspace-dba-scout
fathom berryBOT
# sick egret That is too vague I want a proper error log
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
CAPTURE_DIR="/tmp/openclaw-lobster-repro-$STAMP"
mkdir -p "$CAPTURE_DIR"

echo "capture_dir=$CAPTURE_DIR" | tee "$CAPTURE_DIR/README.txt"
openclaw --version | tee "$CAPTURE_DIR/openclaw-version.txt"
openclaw status --all > "$CAPTURE_DIR/openclaw-status-all.txt" 2>&1
openclaw config get plugins.entries.lobster > "$CAPTURE_DIR/plugin-lobster.txt" 2>&1
openclaw config get plugins.entries.llm-task > "$CAPTURE_DIR/plugin-llm-task.txt" 2>&1
openclaw config get logging.level > "$CAPTURE_DIR/logging-level.txt" 2>&1

LOG_FILE="$(ls -t /tmp/openclaw/openclaw-*.log | head -1)"
echo "$LOG_FILE" > "$CAPTURE_DIR/log-file.txt"
cp "$LOG_FILE" "$CAPTURE_DIR/gateway-before.log" 2>/dev/null || true
fathom berryBOT
# sick egret That is too vague I want a proper error log
timeout 90s openclaw logs --follow --json > "$CAPTURE_DIR/logs-follow.jsonl" 2>&1 &
LOG_PID=$!

timeout 90s env \
  LLM_TASK_PROVIDER=lmstudio \
  LLM_TASK_MODEL='lmstudio/qwen/qwen3.6-35b-a3b' \
  LLM_TASK_THINKING=off \
  LLM_TASK_TIMEOUT_MS=60000 \
  INVOKE_HTTP_TIMEOUT_MS=75000 \
  node lobster-scripts/invoke-llm-task.js \
    < debug-llm-request.json \
    > "$CAPTURE_DIR/invoke.stdout.json" \
    2> "$CAPTURE_DIR/invoke.stderr.txt"

echo "invoke_exit=$?" | tee "$CAPTURE_DIR/invoke-exit.txt"
fathom berryBOT
# sick egret That is too vague I want a proper error log

sleep 2
kill "$LOG_PID" 2>/dev/null || true

cp "$LOG_FILE" "$CAPTURE_DIR/gateway-after.log" 2>/dev/null || true

{
  echo "=== invoke stderr ==="
  cat "$CAPTURE_DIR/invoke.stderr.txt"
  echo
  echo "=== invoke stdout bytes ==="
  wc -c "$CAPTURE_DIR/invoke.stdout.json"
  echo
  echo "=== relevant gateway logs ==="
  rg -i 'lobster|llm-task|tools-invoke|lane wait|queue|timeout|lmstudio|reasoning-only|tool execution failed|error' "$CAPTURE_DIR/logs-follow.jsonl" "$CAPTURE_DIR/gateway-after.log" || true
fathom berryBOT
# sick egret That is too vague I want a proper error log
} | tee "$CAPTURE_DIR/summary.txt"

echo "Capture written to: $CAPTURE_DIR"
  1. Reset logging after capture:
openclaw config set logging.level info
openclaw gateway restart

Paste summary.txt plus invoke-exit.txt. If you file the GitHub issue, attach the whole /tmp/openclaw-lobster-repro-... directory after checking it doesn’t contain secrets. Don’t paste gateway tokens/passwords.

The key things this capture proves are:

  • whether the child process reaches posting to /tools/invoke
fathom berryBOT
sick egret
#

But there aren't any errors in the error log

fathom berryBOT
# sick egret But there aren't any errors in the error log

Right, and that’s exactly why this is a hang/deadlock capture, not an error-log capture. A deadlocked request often produces no error line because nothing throws: one thing is waiting for another thing that can’t start.

So the useful evidence is:

  • child script stderr stops after posting to /tools/invoke
  • no gateway status line ever appears
  • LM Studio sees no request
  • openclaw logs --follow --json during the repro has no nested llm-task execution
  • the command exits only because timeout 90s kills it, usually exit 124

That’s a valid bug report. The “proper error log” is the absence of progress under a bounded timeout, plus timestamps.

If you want an even tighter proof, run these two commands and compare:

# outside Lobster: should complete
fathom berryBOT
# sick egret But there aren't any errors in the error log
timeout 90s node lobster-scripts/invoke-llm-task.js \
  < debug-llm-request.json \
  > /tmp/outside.out \
  2> /tmp/outside.err
echo "outside_exit=$?"
cat /tmp/outside.err

Then run the full Lobster workflow with the same 90s timeout and capture stderr/logs. The contrast is the bug:

outside Lobster: gets gateway status and LM Studio processes
inside Lobster: stops after posting to /tools/invoke, no LM Studio request, no gateway tool execution, killed by timeout

Errors are great when something crashes. Here the failure mode is “no forward progress,” so the report should say hangs/deadlocks without logging an error.

untold solarBOT
fathom berryBOT
# untold solar

Summary of this thread:

Initial ask was how to run the Lobster workflow manually. The manual run path is:

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "lobster",
  "action": "json",
  "args": {
    "action": "run",
    "pipeline": "/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster",
    "timeoutMs": 1800000,
fathom berryBOT
# untold solar
    "maxStdoutBytes": 512000
  }
}
JSON

What we found:

  • Gateway auth had to be fixed first; 401 meant the bearer token/password was wrong or missing.
  • llm-task works manually through /tools/invoke.
  • For this LM Studio/Qwen setup, the working values were effectively provider: "lmstudio" and the model value that worked in their environment was lmstudio/qwen/qwen3.6-35b-a3b.
  • The workflow-generated request had thinking: "low", but the model only supports off; the script must force args.thinking = process.env.LLM_TASK_THINKING || "off";.
  • The hardcoded sessionKey: "agent:lead-scout:main" in invoke-llm-task.js was removed for debugging.
  • Standalone invoke-llm-task.js < debug-llm-request.json works, but the same script hangs when called from inside the embedded Lobster workflow.

Current likely issue:

  • This now looks like a regression/deadlock in embedded Lobster calling back into the same Gateway /tools/invoke path. The nested request hangs before LM Studio sees it, with no error log because it is waiting rather than throwing.
fathom berryBOT
# untold solar

Best next step:

  • File a GitHub issue with version, openclaw status --all, plugin config, and the bounded-timeout repro. The useful repro statement is: “Standalone script works; the same script hangs only as a Lobster workflow step after printing posting to /tools/invoke; LM Studio receives no request; gateway logs show no nested llm-task execution.”

Issue tracker: https://github.com/openclaw/openclaw/issues

Short-term workaround:

  • Avoid nested /tools/invoke from embedded Lobster: call LM Studio directly in that workflow step, run standalone Lobster outside the Gateway, or split the workflow around the LLM step.
sick egret
#

BUt this usually takes 15 mins

fathom berryBOT
# sick egret BUt this usually takes 15 mins

Good correction. If a normal successful run takes ~15 minutes, use a timeout above that for the full workflow capture, like 25 minutes:

timeout 1500s openclaw ...lobster run...

or for the script step:

timeout 1500s node lobster-scripts/invoke-llm-task.js \
  < debug-llm-request.json \
  > debug-draft-email.json \
  2> debug-draft-email-stderr.txt

But one distinction matters: if LM Studio does not start processing within the first minute or two, that is not “the model is slow.” That means the nested request has not reached LM Studio yet. For this bug report, capture both:

fathom berryBOT
# sick egret BUt this usually takes 15 mins
  • a successful standalone run that takes ~15 minutes and shows LM Studio processing
  • the Lobster-run version where it stops after posting to /tools/invoke and LM Studio never starts

So use a long timeout for fairness, but still note whether LM Studio ever receives the request. That’s the key signal.

sick egret
#

The above manual run just hangs too

fathom berryBOT
# sick egret The above manual run just hangs too

If you mean the manual /tools/invoke -> lobster command, then yes, that is still the embedded Gateway Lobster path. It is not an independent/manual execution path; it reproduces the same problem.

There are three different “manual” levels here:

  1. Embedded Lobster via Gateway, still affected:
curl ... /tools/invoke { "tool": "lobster", ... }
  1. The LLM step script outside Lobster, which you said worked:
node lobster-scripts/invoke-llm-task.js < debug-llm-request.json
  1. Standalone Lobster CLI outside the Gateway, if installed. That is the real test for whether Lobster itself can run the workflow without occupying the Gateway tool lane:
fathom berryBOT
# sick egret The above manual run just hangs too
cd /home/admin/.openclaw/workspace-dba-scout
lobster run /home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster

If lobster is not installed, then option 3 is unavailable until you install the standalone Lobster CLI. The curl /tools/invoke tool=lobster route is useful for reproducing the Gateway regression, but it is not a workaround.

sick egret
#

Yep option 1 with the curl just hangs, the pipeline does the first couple of steps but hangs on the invoke

fathom berryBOT
# sick egret Yep option 1 with the curl just hangs, the pipeline does the first couple of ste...

That is the clean repro then:

curl /tools/invoke -> lobster starts
Lobster runs initial shell steps
workflow reaches invoke-llm-task.js
invoke-llm-task.js posts back to /tools/invoke for llm-task
request hangs there; LM Studio does not receive it

So the failure is not the early workflow steps, not auth, and not LM Studio. It is the nested /tools/invoke from inside an embedded Lobster run.

For the issue report, phrase it as:

Regression: embedded Lobster deadlocks when a workflow step calls /tools/invoke.
fathom berryBOT
# sick egret Yep option 1 with the curl just hangs, the pipeline does the first couple of ste...

Repro:
1. Run Lobster through Gateway /tools/invoke.
2. Workflow executes normal shell steps successfully.
3. A later shell step calls /tools/invoke for llm-task.
4. That nested HTTP request hangs indefinitely before tool execution; LM Studio sees no request.
5. Running invoke-llm-task.js standalone with the same stdin works.

That’s specific enough for maintainers to investigate the queue/scheduling path.

sick egret
#

actually, on closer inspection running the pipeline from curl does work

fathom berryBOT
# sick egret actually, on closer inspection running the pipeline from curl does work

That changes the diagnosis. If curl -> /tools/invoke -> lobster works, then embedded Lobster itself is not generally deadlocking.

The remaining difference is likely the context that starts the workflow from chat/agent versus your direct curl call. Compare these:

  • direct curl works
  • chat/agent-triggered Lobster hangs on the invoke step

That points at session/tool policy/queue context, not the workflow file itself.

For the bug report or next debug pass, capture the exact raw params/context for both runs:

Working:
curl /tools/invoke tool=lobster action=run pipeline=...

Failing:
fathom berryBOT
# sick egret actually, on closer inspection running the pipeline from curl does work
same pipeline launched by agent/chat, reaches invoke-llm-task.js, hangs posting to /tools/invoke

The next useful test is to make the failing launch match the working curl as closely as possible:

  • same pipeline
  • same timeoutMs
  • same maxStdoutBytes
  • no sessionKey on the nested llm-task request
  • same gateway token/password
  • same env values: LLM_TASK_MODEL, LLM_TASK_THINKING=off

If curl works reliably, use that as the workaround for now and file the regression as “agent/chat-launched Lobster workflow hangs, direct Gateway curl run succeeds.”

sick egret
#

So is there any more debuging I can do?

fathom berryBOT
# sick egret So is there any more debuging I can do?

Yes. Since direct curl works but the agent/chat-triggered run hangs, debug the differences between launch contexts.

  1. Add this to invoke-llm-task.js before the HTTP request:
console.error("env snapshot:", JSON.stringify({
  OPENCLAW_SESSION_KEY: process.env.OPENCLAW_SESSION_KEY || null,
  OPENCLAW_GATEWAY_URL: process.env.OPENCLAW_GATEWAY_URL || null,
  OPENCLAW_GATEWAY_PORT: process.env.OPENCLAW_GATEWAY_PORT || null,
  LLM_TASK_PROVIDER: process.env.LLM_TASK_PROVIDER || null,
  LLM_TASK_MODEL: process.env.LLM_TASK_MODEL || null,
  LLM_TASK_THINKING: process.env.LLM_TASK_THINKING || null,
  cwd: process.cwd()
}, null, 2));
console.error("payload bytes:", Buffer.byteLength(JSON.stringify(payload)));
fathom berryBOT
# sick egret So is there any more debuging I can do?
  1. Run the working curl-launched Lobster flow and save stderr:
cp debug-draft-email-stderr.txt /tmp/lobster-curl-stderr.txt
  1. Run the failing agent/chat-launched flow and save stderr:
cp debug-draft-email-stderr.txt /tmp/lobster-chat-stderr.txt
  1. Compare them:
diff -u /tmp/lobster-curl-stderr.txt /tmp/lobster-chat-stderr.txt
fathom berryBOT
# sick egret So is there any more debuging I can do?

The most suspicious differences are:

  • OPENCLAW_SESSION_KEY
  • model/thinking env values
  • gateway URL/token source
  • cwd
  • payload bytes
  1. Also capture logs around the failing run only:
openclaw logs --follow --json > /tmp/lobster-chat-logs.jsonl

Then stop it after the hang and filter:

fathom berryBOT
# sick egret So is there any more debuging I can do?
rg -i 'lobster|llm-task|tools-invoke|lane wait|queue|sessionKey|agent:|timeout|failed|lmstudio' /tmp/lobster-chat-logs.jsonl

If curl works and chat does not, the best bug report includes the diff -u plus the filtered logs. That gives maintainers something concrete: same workflow, different launch context, exact env/payload difference.

sick egret
#

The files are the same apart from the chat one just hangs and there are no entries in the log file

fathom berryBOT
# sick egret The files are the same apart from the chat one just hangs and there are no entri...

That narrows it further: the child process reaches the HTTP call, but the Gateway does not log receiving/handling it in the chat-launched case. So debug the TCP/request boundary, not llm-task.

Add these probes inside postJson in invoke-llm-task.js:

req.on("socket", (socket) => {
  console.error("http socket assigned");
  socket.on("lookup", (err, address, family, host) => {
    console.error("http lookup:", { err: err && err.message, address, family, host });
  });
  socket.on("connect", () => {
    console.error("http socket connected");
  });
  socket.on("timeout", () => {
    console.error("http socket timeout");
  });
fathom berryBOT
fathom berryBOT
fathom berryBOT
# sick egret The files are the same apart from the chat one just hangs and there are no entri...
  ...
);

Now rerun the chat-triggered workflow and check stderr. Interpret it like this:

  • no http socket assigned -> Node is stuck before it even opens a socket
  • socket assigned but no socket connected -> TCP connect to Gateway is stuck/refused somewhere
  • socket connected but no gateway status and no Gateway logs -> Gateway accepted the socket but is not processing the HTTP request
  • gateway status appears -> we’re past the hang and back to tool execution

While it is hung, also run from another terminal:

curl --max-time 5 -v http://127.0.0.1:18789/tools/invoke \
fathom berryBOT
# sick egret The files are the same apart from the chat one just hangs and there are no entri...
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"tool":"llm-task","action":"json","args":{"provider":"lmstudio","model":"lmstudio/qwen/qwen3.6-35b-a3b","thinking":"off","prompt":"Return {"ok":true}","maxTokens":20,"timeoutMs":10000}}'

If that terminal curl also hangs while the chat-launched Lobster is hung, the Gateway HTTP server/event loop is blocked by that chat-triggered run. If the terminal curl works, the stuck child process/socket details will tell us what’s different.

sick egret
fathom berryBOT
# sick egret Can you write the whole file here https://cl1p.net/4570

Done: https://cl1p.net/4570

This version includes:

  • socket probes: assigned / connected / timeout / close / errors
  • family: 4 to force IPv4
  • agent: false and connection: close to avoid connection reuse
  • env snapshot + payload byte logging
  • forced thinking: "off"
  • no session key unless OPENCLAW_SESSION_KEY is explicitly set

After you rerun the chat-triggered workflow, the important stderr lines are whether it reaches:

http socket assigned
http socket connected
http request body flushed
http response headers received
fathom berryBOT
sick egret
#

The curl now fails, here is the stderr file

stdin bytes: 19327
env snapshot: {
"OPENCLAW_SESSION_KEY": null,
"OPENCLAW_GATEWAY_URL": null,
"OPENCLAW_GATEWAY_PORT": "18789",
"LLM_TASK_PROVIDER": null,
"LLM_TASK_MODEL": null,
"LLM_TASK_THINKING": null,
"cwd": "/home/admin"
}
llm-task args: {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"thinking": "off",
"timeoutMs": 600000,
"maxTokens": 8000,
"temperature": 0,
"requestTimeoutMs": 900000,
"sessionKey": null
}
payload bytes: 19448
posting to: http://127.0.0.1:18789/tools/invoke
has bearer auth: true
http request body bytes: 19448
http request writing body
http request end called
http socket assigned
http socket connected
http request body flushed
http response headers received: { statusCode: 500, statusMessage: 'Internal Server Error' }
http response chunk bytes: 76
http response end bytes: 76
gateway status: 500 Internal Server Error
gateway response bytes: 76
Gateway HTTP request failed
URL: http://127.0.0.1:18789/tools/invoke
Status: 500 Internal Server Error
Raw response:
{"ok":false,"error":{"type":"tool_error","message":"tool execution failed"}}

fathom berryBOT
# sick egret The curl now fails, here is the stderr file stdin bytes: 19327 env snapshot: { ...

Good, this is a real failure now, not a socket hang. The request reaches the Gateway and the Gateway returns a tool error:

http socket connected
http response headers received: 500
{"ok":false,"error":{"type":"tool_error","message":"tool execution failed"}}

So the next evidence is the Gateway log line at the same timestamp. Run this immediately after the failed curl/script run:

openclaw logs --tail 200 | rg -i 'llm-task|tools-invoke|tool execution failed|empty output|invalid json|thinking|lmstudio|provider|model|timeout|error'

If that misses it, use the raw file:

fathom berryBOT
fathom berryBOT
# sick egret The curl now fails, here is the stderr file stdin bytes: 19327 env snapshot: { ...

That may matter if the prompt/input references relative paths. For the next standalone test, run it from the workflow dir:

cd /home/admin/.openclaw/workspace-dba-scout

node lobster-scripts/invoke-llm-task.js \
  < debug-llm-request.json \
  > debug-draft-email.json \
  2> debug-draft-email-stderr.txt

But the 500 itself is now a Gateway-side llm-task failure, so the log line should tell us whether it is invalid JSON, empty output, timeout, model config, or something else.

sick egret
#

18:44:01
warn
tools-invoke
tool execution failed: Error: LLM returned invalid JSON
18:44:01
warn
tools-invoke
tool execution failed: Error: workflow command failed (1): sh -c 'node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js 2> /home/admin/.openclaw/workspace-dba-scout/debug-draft-email-stderr.txt'

fathom berryBOT
# sick egret 18:44:01 warn tools-invoke tool execution failed: Error: LLM returned invalid JS...

Now we have the actual error:

LLM returned invalid JSON

So Gateway/Lobster/invoke are working. The model is returning visible text, but llm-task cannot parse it as JSON.

Because llm-task only returns the sanitized 500 here, the fastest debug is to bypass llm-task once and call LM Studio directly with the exact prompt from debug-llm-request.json, saving the raw model text.

Run:

cd /home/admin/.openclaw/workspace-dba-scout

jq -r '.prompt' debug-llm-request.json > /tmp/sql-leads-prompt.txt
fathom berryBOT
fathom berryBOT
# sick egret 18:44:01 warn tools-invoke tool execution failed: Error: LLM returned invalid JS...

curl -sS http://127.0.0.1:1234/v1/chat/completions \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/lmstudio-debug-request.json \
  | tee /tmp/lmstudio-debug-response.json \
  | jq -r '.choices[0].message.content' \
  | tee /tmp/lmstudio-debug-content.txt

jq . /tmp/lmstudio-debug-content.txt

That final jq . /tmp/lmstudio-debug-content.txt is expected to show the parse problem. Look for:

  • <think> or reasoning text before the JSON
  • markdown fences like ```json
  • prose before/after the JSON
  • truncated JSON because maxTokens is too low
fathom berryBOT
sick egret
#

The curl output this
{
"subject": "SQL Optimization & Licensing Savings",
"leads": []
}
{
"subject": "SQL Optimization & Licensing Savings",
"leads": []
}

fathom berryBOT
# sick egret The curl output this { "subject": "SQL Optimization & Licensing Savings", "l...

That output is valid JSON, but it looks like it was printed twice. If the actual model content is two JSON objects back-to-back, llm-task will reject it as invalid JSON because this is not one JSON value:

{ ... }
{ ... }

Confirm with:

wc -c /tmp/lmstudio-debug-content.txt
cat -n /tmp/lmstudio-debug-content.txt
jq . /tmp/lmstudio-debug-content.txt

If cat -n shows two objects, that’s the bug. Tighten the prompt in build-llm-request.js to say:

fathom berryBOT
# sick egret The curl output this { "subject": "SQL Optimization & Licensing Savings", "l...
Return exactly one JSON object.
Do not repeat the JSON.
Do not include a second copy.
Do not include markdown or commentary.
The response must be parseable by JSON.parse as a single value.

Also, your shown JSON has "leads": []. If the workflow expected actual leads, then the prompt/input mapping may be wrong too, but the immediate llm-task failure is likely duplicate JSON objects.

sick egret
#

73 /tmp/lmstudio-debug-content.txt
1
2
3 {
4 "subject": "SQL Optimization & Licensing Savings",
5 "leads": []
6 }
{
"subject": "SQL Optimization & Licensing Savings",
"leads": []
}

fathom berryBOT
# sick egret 73 /tmp/lmstudio-debug-content.txt 1 2 3 { 4 "subject": ...

That file is actually one valid JSON object. The second copy you pasted is probably jq . /tmp/lmstudio-debug-content.txt re-printing the parsed object, not a duplicate in the file.

So the direct LM Studio prompt is valid, but it still doesn’t exactly match what llm-task sends. llm-task wraps your request like this:

You are a JSON-only function...
TASK:
<debug-llm-request.json .prompt>

INPUT_JSON:
<debug-llm-request.json .input>

Test that exact shape directly:

fathom berryBOT
fathom berryBOT
# sick egret 73 /tmp/lmstudio-debug-content.txt 1 2 3 { 4 "subject": ...
/no_think
Return exactly one valid JSON object and nothing else."
' debug-llm-request.json > /tmp/llm-task-exact-prompt.txt

jq -n --rawfile prompt /tmp/llm-task-exact-prompt.txt '{
  model: "lmstudio/qwen/qwen3.6-35b-a3b",
  messages: [{ role: "user", content: $prompt }],
  temperature: 0,
  max_tokens: 8000
}' > /tmp/llm-task-exact-lmstudio-request.json

curl -sS http://127.0.0.1:1234/v1/chat/completions \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/llm-task-exact-lmstudio-request.json \
  | tee /tmp/llm-task-exact-lmstudio-response.json \
fathom berryBOT
# sick egret 73 /tmp/lmstudio-debug-content.txt 1 2 3 { 4 "subject": ...
  | jq -r '.choices[0].message.content' \
  | tee /tmp/llm-task-exact-content.txt

cat -n /tmp/llm-task-exact-content.txt
jq . /tmp/llm-task-exact-content.txt

If that parses, then the remaining difference is OpenClaw’s embedded runner/transport, not the model’s raw ability to produce JSON. If that fails, the shown content tells you exactly what llm-task is choking on.

sick egret
#

I get this

 1
fathom berryBOT
# sick egret I get this 1

That means /tmp/llm-task-exact-content.txt is empty or only whitespace. So with the exact llm-task-style prompt, LM Studio returned no visible content. That matches the earlier LLM returned empty output / invalid JSON behavior.

Check whether the response has reasoning or another field instead of .choices[0].message.content:

jq . /tmp/llm-task-exact-lmstudio-response.json | head -120
jq '.choices[0].message' /tmp/llm-task-exact-lmstudio-response.json

Also check the prompt size:

wc -c /tmp/llm-task-exact-prompt.txt
head -40 /tmp/llm-task-exact-prompt.txt
tail -40 /tmp/llm-task-exact-prompt.txt
fathom berryBOT
# sick egret I get this 1

My read now: the llm-task wrapper plus your generated prompt is causing this Qwen reasoning model to produce no visible answer. The simpler direct prompt works, but the exact wrapped prompt does not.

Practical fixes:

  • simplify debug-llm-request.json so .prompt does not already contain a full system-style instruction block
  • move the leads data into .input and keep .prompt short
  • use a non-reasoning instruct model for this JSON step
  • or skip llm-task and call LM Studio directly with the simpler prompt that already produced valid JSON

If you paste jq '.choices[0].message' /tmp/llm-task-exact-lmstudio-response.json, we can see whether the model put the answer somewhere weird or genuinely returned empty content.

sick egret
untold solarBOT
fathom berryBOT
# sick egret The output can be found here https://cl1p.net/4571

This output explains the failure.

LM Studio is returning:

"content": "",
"reasoning_content": "The user wants ... Generating JSON. ```json { ..."

So the model is putting everything, including the would-be JSON, into reasoning_content, while the visible assistant content is empty. llm-task only parses visible final text, so it either sees empty output or invalid JSON. That is why Gateway reports:

LLM returned invalid JSON

This is no longer Lobster. It is the model/API response shape.

fathom berryBOT
# sick egret The output can be found here https://cl1p.net/4571

Fix options:

  1. Best: disable reasoning/thinking output for this Qwen model in LM Studio so the final JSON appears in message.content, not message.reasoning_content.

  2. Use a non-reasoning/instruct model for this JSON workflow step.

  3. Stop using llm-task for this model and call LM Studio directly from the Lobster step, reading from:

choice.message.content || choice.message.reasoning_content

then extract the JSON yourself.

For llm-task to work, this command must print actual JSON:

fathom berryBOT
fathom berryBOT
# untold solar

Thread summary:

Initial question: how to run the Lobster workflow manually.

Manual run through Gateway:

curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "lobster",
  "action": "json",
  "args": {
    "action": "run",
fathom berryBOT
# untold solar
    "pipeline": "/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster",
    "timeoutMs": 1800000,
    "maxStdoutBytes": 512000
  }
}
JSON

Main debugging findings:

  • 401 Unauthorized was Gateway auth, fixed by using the correct token/password bearer.
  • The llm-task model args that worked in this environment used provider: "lmstudio" and model: "lmstudio/qwen/qwen3.6-35b-a3b".
  • The workflow was passing thinking: "low", but the model only supports off; the script should force args.thinking = process.env.LLM_TASK_THINKING || "off";.
  • The hardcoded sessionKey was removed for debugging.
  • Later logs showed the real failure was LLM returned invalid JSON.

Final root cause found:

fathom berryBOT
# untold solar

LM Studio/Qwen returned the generated answer in message.reasoning_content while message.content was empty. llm-task only parses visible content, so it saw empty/invalid output even though LM Studio had generated text.

Fix options:

  • Best: disable reasoning/thinking output for that Qwen model in LM Studio so JSON appears in message.content.
  • Use a non-reasoning/instruct model for this JSON workflow step.
  • Or bypass llm-task for this step and call LM Studio directly, reading message.content || message.reasoning_content, then extracting/parsing the JSON in the script.

If this resolved the original issue, please right-click the solution message -> Apps -> âś… Mark Solution so Answer Overflow indexes it.

sick egret
#

But doesn't the invoke script disable reasoning?

fathom berryBOT
# sick egret But doesn't the invoke script disable reasoning?

It disables reasoning from OpenClaw’s side, yes:

args.thinking = process.env.LLM_TASK_THINKING || "off";

But that only tells OpenClaw/llm-task to request thinking: off. It does not guarantee LM Studio or that Qwen model will put the final answer in message.content.

Your raw LM Studio response showed the important bit:

"content": "",
"reasoning_content": "..."

So either LM Studio is still exposing the model’s reasoning channel despite the OpenClaw thinking: off request, or the OpenAI-compatible adapter is mapping the model output into reasoning_content anyway.

fathom berryBOT
# sick egret But doesn't the invoke script disable reasoning?

That means thinking: off is necessary, but not sufficient for this model/server combo. For llm-task to work, the final JSON must appear in:

choices[0].message.content

not only in:

choices[0].message.reasoning_content

So the fixes are still: disable reasoning in LM Studio/model settings, use a non-reasoning instruct model, or bypass llm-task and have your script read content || reasoning_content before extracting JSON.

sick egret
#

ok, I've disabled it, how do I test?

fathom berryBOT
# sick egret ok, I've disabled it, how do I test?

Test in three layers.

  1. Verify LM Studio now puts text in message.content:
cd /home/admin/.openclaw/workspace-dba-scout

curl -sS http://127.0.0.1:1234/v1/chat/completions \
  -H 'Content-Type: application/json' \
  --data-binary @/tmp/llm-task-exact-lmstudio-request.json \
  | tee /tmp/lmstudio-after-disable-response.json \
  | jq '.choices[0].message | {content, reasoning_content}'

You want content to contain the JSON, and reasoning_content to be null/empty/missing.

  1. Test llm-task directly:
fathom berryBOT
# sick egret ok, I've disabled it, how do I test?
node lobster-scripts/invoke-llm-task.js \
  < debug-llm-request.json \
  > debug-draft-email.json \
  2> debug-draft-email-stderr.txt

cat debug-draft-email-stderr.txt
jq . debug-draft-email.json

You want no LLM returned invalid JSON, and jq should parse the output.

  1. Then rerun the Lobster workflow:
curl -sS http://127.0.0.1:18789/tools/invoke \
fathom berryBOT
# sick egret ok, I've disabled it, how do I test?
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
{
  "tool": "lobster",
  "action": "json",
  "args": {
    "action": "run",
    "pipeline": "/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster",
    "timeoutMs": 1800000,
    "maxStdoutBytes": 512000
  }
}
JSON
fathom berryBOT
sick egret
#

All three worked

fathom berryBOT
# sick egret All three worked

Great, then the final fix is confirmed: LM Studio/Qwen was returning the answer in reasoning_content instead of visible message.content. Disabling reasoning for that model made llm-task receive parseable JSON, and the Lobster workflow works again.

Please mark the solution so this gets indexed:

Right-click the solution message -> Apps -> âś… Mark Solution

sick egret
#

No. Its not fixed. If I run the lobster from a prompt it still hangs. I don't see lmstudio processing and this is in the stderr file
stdin bytes: 19327
env snapshot: {
"OPENCLAW_SESSION_KEY": null,
"OPENCLAW_GATEWAY_URL": null,
"OPENCLAW_GATEWAY_PORT": "18789",
"LLM_TASK_PROVIDER": null,
"LLM_TASK_MODEL": null,
"LLM_TASK_THINKING": null,
"cwd": "/home/admin"
}
llm-task args: {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"thinking": "off",
"timeoutMs": 600000,
"maxTokens": 8000,
"temperature": 0,
"requestTimeoutMs": 900000,
"sessionKey": null
}
payload bytes: 19448
posting to: http://127.0.0.1:18789/tools/invoke
has bearer auth: true
http request body bytes: 19448
http request writing body
http request end called
http socket assigned
http socket connected
http request body flushed

fathom berryBOT
# sick egret No. Its not fixed. If I run the lobster from a prompt it still hangs. I don't se...

You’re right, I overstated it. What’s fixed is the LM Studio reasoning/JSON issue. This new stderr is a different failure mode.

This line sequence is the key:

http socket connected
http request body flushed
# no response headers
# LM Studio never starts

That means the nested HTTP request reached the Gateway socket, but the Gateway never got as far as executing llm-task. So this is back to launch-context/queueing, specifically when Lobster is started “from a prompt”.

Current matrix:

  • Direct invoke-llm-task.js < debug-llm-request.json: works
  • Direct curl /tools/invoke -> lobster: works
fathom berryBOT
# sick egret No. Its not fixed. If I run the lobster from a prompt it still hangs. I don't se...
  • Prompt/agent-started Lobster -> workflow shell step -> /tools/invoke llm-task: hangs before llm-task

That strongly points to a re-entrant scheduling bug in the agent/prompt-launched tool path. The nested /tools/invoke is waiting for the Gateway/tool lane while the prompt-triggered Lobster call is already occupying it.

Useful repro wording for GitHub:

Regression: Lobster workflow with nested /tools/invoke works when launched by external curl, but hangs when launched from an agent prompt.

The workflow reaches a shell step that posts to http://127.0.0.1:18789/tools/invoke for llm-task.
The child process logs:
  http socket connected
  http request body flushed
but never receives response headers. LM Studio never receives the request. Direct curl-launched Lobster and direct invoke-llm-task.js both work with the same payload.

Workaround for now: launch this workflow via external curl/CLI instead of asking the agent to run Lobster from a prompt, or make the workflow call LM Studio directly for that step. The prompt-launched nested tool path looks broken.

sick egret
#

Can you help me file in githib issue

fathom berryBOT
# sick egret Can you help me file in githib issue

I can help draft it, but I can’t file GitHub issues on your behalf. Please file it here: https://github.com/openclaw/openclaw/issues

Suggested title:

Regression: prompt-launched Lobster workflow hangs on nested /tools/invoke, while curl-launched workflow works

Suggested issue body:

## Summary

A Lobster workflow that calls `/tools/invoke` from a shell step hangs when the Lobster workflow is launched from an agent prompt/chat.

The same workflow works when launched directly via external `curl /tools/invoke`, and the same nested invoke script works standalone with the same input.
fathom berryBOT
# sick egret Can you help me file in githib issue

This appears to be specific to the prompt/agent-launched Lobster execution context.

## Version

```bash
openclaw --version

Paste output here.

Workflow shape

The Lobster workflow runs initial shell steps successfully, then reaches:

fathom berryBOT
# sick egret Can you help me file in githib issue
  • id: draft_email
    command: sh -c 'node /home/admin/.openclaw/workspace-dba-scout/lobster-scripts/invoke-llm-task.js 2> /home/admin/.openclaw/workspace-dba-scout/debug-draft-email-stderr.txt'
    stdin: $debug_llm_request.stdout

That script posts to:

```text
http://127.0.0.1:18789/tools/invoke

to invoke llm-task.

Expected behavior

Prompt-launched Lobster should behave like curl-launched Lobster: the nested /tools/invoke request should execute llm-task and return a response, or fail fast with a clear error if nested invokes are unsupported in that context.

fathom berryBOT
# sick egret Can you help me file in githib issue

## Actual behavior

When launched from an agent prompt/chat, the workflow reaches the invoke step and hangs. LM Studio never receives the request.

The stderr from the child process ends here:

```text
stdin bytes: 19327
env snapshot: {
  "OPENCLAW_SESSION_KEY": null,
  "OPENCLAW_GATEWAY_URL": null,
  "OPENCLAW_GATEWAY_PORT": "18789",
  "LLM_TASK_PROVIDER": null,
  "LLM_TASK_MODEL": null,
  "LLM_TASK_THINKING": null,
fathom berryBOT
# sick egret Can you help me file in githib issue

"cwd": "/home/admin"
}
llm-task args: {
"provider": "lmstudio",
"model": "lmstudio/qwen/qwen3.6-35b-a3b",
"thinking": "off",
"timeoutMs": 600000,
"maxTokens": 8000,
"temperature": 0,
"requestTimeoutMs": 900000,
"sessionKey": null
}
payload bytes: 19448
posting to: http://127.0.0.1:18789/tools/invoke
has bearer auth: true
http request body bytes: 19448
http request writing body

fathom berryBOT
# sick egret Can you help me file in githib issue

http request end called
http socket assigned
http socket connected
http request body flushed


No `http response headers received` line appears.

## What works

The same workflow works when launched directly with curl:

```bash
curl -sS http://127.0.0.1:18789/tools/invoke \
  -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON' | jq
fathom berryBOT
# sick egret Can you help me file in githib issue

{
"tool": "lobster",
"action": "json",
"args": {
"action": "run",
"pipeline": "/home/admin/.openclaw/workspace-dba-scout/sql-leads-draft.lobster",
"timeoutMs": 1800000,
"maxStdoutBytes": 512000
}
}
JSON


The same invoke script also works standalone:

```bash
cd /home/admin/.openclaw/workspace-dba-scout
fathom berryBOT
# sick egret Can you help me file in githib issue

node lobster-scripts/invoke-llm-task.js
< debug-llm-request.json \

debug-draft-email.json
2> debug-draft-email-stderr.txt


## Notes

Earlier debugging found and fixed a separate LM Studio/Qwen issue: the model was returning output in `reasoning_content` instead of `message.content`. Disabling reasoning in LM Studio fixed that. The remaining issue is different: in the failing prompt-launched Lobster path, LM Studio never receives the request at all.

## Suspected cause

Possible re-entrant scheduling/queue issue when an agent/prompt-launched Lobster tool call runs a shell step that calls back into the same Gateway `/tools/invoke` endpoint.

The nested HTTP request connects and flushes its body, but Gateway never returns response headers and the nested `llm-task` execution does not appear to start.
fathom berryBOT