langgenius/dify · error · BaseError

UsageInvalidFlag

UsageInvalidFlag

Error message

workflow apps do not accept a positional message

What it means

Thrown by `executeRun` (run/app/run.ts:71) when the resolved app mode is `Workflow` and a positional `message` argument was also supplied (`opts.message` is a non-empty string). Workflow apps take structured `inputs`, not a free-text message, so combining them is rejected as `usage_invalid_flag` (exit 2) with a hint pointing to `--inputs`.

Source

Thrown at cli/src/commands/run/app/run.ts:71

      throw err.withHint(
        'app metadata cache cleared — if the app was recently republished, run the command again',
      )
    }
    throw err
  }
}

async function executeRun(
  opts: RunAppOptions,
  deps: RunAppDeps,
  meta: AppMetaClient,
): Promise<void> {
  const m = await meta.get(opts.appId, [FieldInfo])
  const mode = m.info?.mode ?? ''
  if (mode === '') throw new Error(`app ${opts.appId}: mode missing from app metadata`)

  if (mode === RUN_MODES.Workflow && opts.message !== undefined && opts.message !== '') {
    throw new BaseError({
      code: ErrorCode.UsageInvalidFlag,
      message: 'workflow apps do not accept a positional message',
      hint: 'pass workflow inputs via --inputs \'{"key":"value"}\'',
    })
  }

  const inputs = await resolveInputs(opts.inputsJson, opts.inputsFile, opts.inputs)
  if (opts.files !== undefined && opts.files.length > 0) {
    const uploadClient = new FileUploadClient(deps.http)
    const fileInputs = await resolveFileInputs(opts.appId, opts.files, (appId, path) =>
      uploadClient.upload(appId, path),
    )
    Object.assign(inputs, fileInputs)
  }
  const format = opts.format ?? ''
  const isText = TEXT_FORMATS.has(format)
  const livePrint = opts.stream === true
  const runClient = new AppRunClient(deps.http)

View on GitHub (pinned to ef8544b173)

Solutions

  1. Drop the positional message and pass workflow inputs via `--inputs '{"key":"value"}'`.
  2. Confirm the app type with `difyctl describe app <uuid>`; if it should accept a message, it is not a workflow app.
  3. Update scripts to branch on app mode before choosing message vs inputs.

Example fix

// before
$ difyctl run app <workflow-uuid> "summarize this"
// after
$ difyctl run app <workflow-uuid> --inputs '{"text":"summarize this"}'
Defensive patterns

Strategy: validation

Validate before calling

// Resolve mode first; only pass a message for non-workflow apps.
const mode = await getAppMode(appId)
if (mode === 'workflow' && opts.message) {
  throw new Error('workflow apps take --inputs, not a message')
}

Type guard

function isWorkflowMode(mode: string): boolean {
  return mode === 'workflow'
}

Prevention

When it happens

Trigger: Running `difyctl run app <workflow-uuid> "hello"` or `--message "hello"` against an app whose metadata `mode === 'workflow'`. The guard at line 70 checks mode and non-empty message.

Common situations: User reuses a chat/completion invocation pattern on a workflow app; misidentifies the app type; scripting template assumes a message arg uniformly.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/0349419045b45c1b. Report an issue: GitHub.