Skip to main content

Where Output Goes

A command’s result is always JSON on stdout. Errors and notices go to stderr:
  • Errors: as text in your terminal, and as JSON when you send stderr to a file or another program, such as with 2> errors.log. To get errors as JSON in your terminal too, add --json.
  • Notices, such as stream ended early: …: always as plain text.

Read a Run’s Result

The result of a run console_app command holds the app’s answer and the IDs you’ll need next:

Check How a Run Ended

In a script, read the result’s status. A run that finished, paused, or was cut off exits 0 all the same, and status tells them apart:
  • ended: the run finished.
  • suspended: the run paused at a Human Input form. Its hints carry one command per action button: to answer the form, run the one for your action.
  • incomplete: the result was cut off before the run ended, for example when you press Ctrl+C. It holds only what arrived by then. A Workflow or Chatflow run keeps going on the server: to see how it ends, pass the result’s run_id to difyctl describe run.
  • failed (exit code 1): the run failed or was stopped, and error.message says why.
A failed run prints its result on stdout like any other run, and nothing goes to stderr. For example, a Workflow run without its required input:

Read an Error

A command that fails before it produces a result prints nothing on stdout and an error on stderr. Here’s the error as JSON for an app ID that doesn’t exist:
Every error has a code and a message. Branch on code. Depending on the failure, the error also carries:
  • hint: what to try next, as a sentence, such as run difyctl help get console_app.
  • http_status, method, url, and server (the server’s own error), when the server returned the error. For server_error, branch on http_status or server.code, such as 404 and not_found above.
  • details, when a value fails difyctl’s own check (input_invalid): each field that failed, with its flag and the reason, such as "field": "--limit", "msg": "must be integer".
In a terminal, the error’s first line shows the server’s own code when there is one. For the missing app above, that’s not_found: app not found. Take the codes your script branches on from the JSON, where this one is server_error. When message doesn’t explain the failure, add --verbose to include raw_response, the server’s full response.

Exit Codes

Every command exits with one of these codes: On exit code 1, look at stdout first: a failed run’s result is there. Any other error is on stderr. To fix a specific error, see Troubleshooting.

Retry a Failed Command

Commands that read, such as get and describe, are safe to retry. help shows each command’s label, read, write, or destructive, next to its description. Before you retry a write or destructive command, check whether the first attempt took effect, for example with the matching get or describe command. A run is write, and retrying it starts a new run. After exit code 7, any command is safe to retry, runs included: a command refused by the rate limit did nothing on the server. Exit codes 2 and 4 come back on every retry until you fix the cause, such as a wrong flag or an expired sign-in.

Rate Limit

When a command exits 7, wait a minute, then retry. Each sign-in gets 60 requests a minute by default. To change the limit, set OPENAPI_RATE_LIMIT_PER_TOKEN on your server, or set it to 0 to turn the limit off.

Troubleshooting

Last modified on October 23, 2026