langgenius/dify · error · BaseError

UsageInvalidFlag

UsageInvalidFlag

Error message

invalid --role "${opts.role}"

What it means

Thrown by `runSetMember` (set/member/run.ts:47) as `usage_invalid_flag` (exit 2) when `opts.role` is not in the assignable set `{normal, admin}`. Ownership transfer is intentionally excluded (console-only) per the hint. The check uses an exact-match `Set.has`, so case variants like `Admin` or aliases like `owner`/`member` are rejected.

Source

Thrown at cli/src/commands/set/member/run.ts:47

  readonly data: SetMemberOutput
  readonly workspaceId: string
}

const ASSIGNABLE_ROLES = new Set(['normal', 'admin'])

export async function runSetMember(
  opts: SetMemberOptions,
  deps: SetMemberDeps,
): Promise<SetMemberResult> {
  if (opts.memberId === undefined || opts.memberId === '') {
    throw new BaseError({
      code: ErrorCode.UsageMissingArg,
      message: 'member id is required',
      hint: 'pass it positionally: difyctl set member <member-id> --role <role>',
    })
  }
  if (!ASSIGNABLE_ROLES.has(opts.role)) {
    throw new BaseError({
      code: ErrorCode.UsageInvalidFlag,
      message: `invalid --role "${opts.role}"`,
      hint: 'expected: normal | admin (ownership transfer is console-only)',
    })
  }

  const env = deps.envLookup ?? ((k: string) => process.env[k])
  const factory = deps.membersFactory ?? ((h: HttpClient) => new MembersClient(h))
  const io = deps.io ?? nullStreams()
  const cs = colorScheme(colorEnabled(io.isErrTTY))

  const wsId = resolveWorkspaceId({
    flag: opts.workspace,
    env: env('DIFY_WORKSPACE_ID'),
    active: deps.active,
  })

  await runWithSpinner({ io, label: `Updating role for ${opts.memberId}` }, () =>

View on GitHub (pinned to ef8544b173)

Solutions

  1. Use exactly `--role normal` or `--role admin` (lowercase).
  2. For ownership transfer, perform it in the Dify web console (CLI does not support it).
  3. Double-check the role vocabulary against the workspace members API.

Example fix

// before
$ difyctl set member <id> --role owner
// after
$ difyctl set member <id> --role admin
Defensive patterns

Strategy: validation

Validate before calling

const ASSIGNABLE_ROLES = new Set(['normal', 'admin'])
function isAssignableRole(role: string): boolean {
  return ASSIGNABLE_ROLES.has(role)
}

Type guard

type AssignableRole = 'normal' | 'admin'
function isAssignableRole(v: unknown): v is AssignableRole {
  return v === 'normal' || v === 'admin'
}

Prevention

When it happens

Trigger: Passing `--role owner`, `--role member`, `--role Admin` (wrong case), `--role editor`, or any value outside `{normal, admin}`. Fires at line 46 after the memberId check.

Common situations: User attempts ownership transfer via CLI (blocked by design); uses a role name from a different IAM system; passes uppercase or localized role labels.

Related errors


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