langgenius/dify · error · Error

app ${opts.appId}: mode missing from app metadata

Error message

app ${opts.appId}: mode missing from app metadata

What it means

Thrown by `executeRun` (run/app/run.ts:68) as a plain `Error` (no code → exit 1) when the app metadata fetch (`meta.get(appId, [FieldInfo])`) returns an object whose `info?.mode` is empty/undefined. The CLI cannot pick a run strategy without knowing the app mode (workflow vs chat vs completion), so it aborts. This is a data/state defect, not a usage error.

Source

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

  } catch (err) {
    if (err instanceof HttpClientError && err.httpStatus === 422) {
      await meta.invalidate(opts.appId)
      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 ?? ''

View on GitHub (pinned to ef8544b173)

Solutions

  1. Bypass the cache: re-run with the describe/run refresh flag (`--refresh`) or clear the app-info cache.
  2. Verify the app is fully published and has a mode via the console or `GET /v1/apps/{id}`.
  3. If version skew is suspected, align the CLI version with the Dify server release.
  4. If the issue persists, inspect the raw metadata response to confirm `mode` is genuinely absent.
Defensive patterns

Strategy: try-catch

Validate before calling

// Defensive check before runApp: confirm mode is present.
const meta = await new AppMetaClient({ apps, host, cache }).get(appId, [FieldInfo])
const mode = meta.info?.mode
if (!mode) throw new Error(`app ${appId} has no mode; republish or refresh`)

Type guard

function hasAppMode(m: { info?: { mode?: string } } | undefined): m is { info: { mode: string } } {
  return typeof m?.info?.mode === 'string' && m.info.mode !== ''
}

Try / catch

try {
  await runApp(opts, deps)
} catch (err) {
  if (err instanceof Error && /mode missing from app metadata/.test(err.message)) {
    // clear cache, republish/verify the app, then retry once
  }
  throw err
}

Prevention

When it happens

Trigger: The Dify server returns app metadata without a `mode` field — possible with a partially provisioned app, a malformed cache entry, an app in an incomplete state, or API version skew where the mode field was renamed/removed. The cached `AppInfoCache` could also hold a stale entry missing the field.

Common situations: App was created via API but not fully published; CLI/server version mismatch where the mode field moved; corrupted cache; the app is a deleted/draft artifact; a proxy stripped fields.

Related errors


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