ory/kratos · error

invalid --start-after format

Error message

invalid --start-after format %q: expected key=uuid (e.g. credentials=<id>)

What it means

parseStartAfter parses --start-after flags expected in the form "key=uuid" (e.g. credentials=<id>). If an argument contains no '=' separator, strings.Cut fails and this error is returned, echoing the offending argument. It is a CLI argument format validation error, raised before any database work.

Solutions

  1. Provide the value as key=uuid, e.g. --start-after credentials=018f3c2e-....
  2. Quote the argument in shells where '=' or the value could be split.
  3. Check `--help` for the exact expected format of --start-after.

Example fix

// before
kratos migrate normalize-phone --start-after 018f3c2e-3f4a-7b8c-9d0e-1f2a3b4c5d6e
// after
kratos migrate normalize-phone --start-after credentials=018f3c2e-3f4a-7b8c-9d0e-1f2a3b4c5d6e
Defensive patterns

Strategy: validation

Validate before calling

for _, a := range startAfterFlags {
    if !strings.Contains(a, "=") {
        return fmt.Errorf("--start-after must be key=uuid, got %q", a)
    }
}

Type guard

func validStartAfter(arg string) bool {
    k, v, ok := strings.Cut(arg, "=")
    _, err := uuid.Parse(v)
    return ok && k != "" && err == nil
}

Try / catch

null

Prevention

When it happens

Trigger: Passing --start-after a value without '=' such as `--start-after credentials` or `--start-after 018f-...` instead of `--start-after credentials=<uuid>`.

Common situations: Copy-pasting only the UUID or only the key from a previous run's resume hint, shell quoting dropping the '=' (rare), or confusing this flag's format with other resume-style flags.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/e0b7b46c3de02b46. Report an issue: GitHub.

Appendix: source

Thrown at cmd/migrate/normalize_phone_handler.go:130

	printSummary(cmd, tables, allStats)

	return nil
}

type tableConfig struct {
	key         string
	name        string
	selectQuery string
	updateQuery string
}

// parseStartAfter parses --start-after flags of the form "key=uuid".
func parseStartAfter(args []string) (map[string]uuid.UUID, error) {
	result := make(map[string]uuid.UUID)
	for _, arg := range args {
		key, val, ok := strings.Cut(arg, "=")
		if !ok {
			return nil, errors.Errorf("invalid --start-after format %q: expected key=uuid (e.g. credentials=<id>)", arg)
		}
		id, err := uuid.FromString(val)
		if err != nil {
			return nil, errors.Wrapf(err, "invalid UUID in --start-after %q", arg)
		}
		result[key] = id
	}
	return result, nil
}

func printSummary(cmd *cobra.Command, tables []tableConfig, allStats []normalizeStats) {
	out := cmd.OutOrStdout()

	_, _ = fmt.Fprintln(out)

	tw := tabwriter.NewWriter(out, 0, 0, 2, ' ', 0)
	_, _ = fmt.Fprintln(tw, "\tSCANNED\tUPDATED\tSKIPPED\tERRORS")

View on GitHub (pinned to b86338da04)