chenhg5/cc-connect · error

PreflightRunAsUser: RunAsUser is empty

Error message

PreflightRunAsUser: RunAsUser is empty

What it means

PreflightRunAsUser runs startup safety checks for the run_as_user sandbox and returns a PreflightResult. When cfg.RunAsUser is empty it appends this error to result.Fatal and returns immediately — the sandbox cannot be validated without a target user, so startup must be treated as failed. Unlike the plain probe, the error is carried inside the result's Fatal list rather than returned directly.

Source

Thrown at core/runas_check.go:85

// PreflightRunAsUser runs all three startup safety checks for a single
// project. It never panics and never returns nil; instead all problems are
// accumulated into the returned PreflightResult for the caller to aggregate
// and log.
//
// Checks:
//
//  1. Passwordless sudo -iu <target> is configured (fatal if missing).
//  2. Target user has no passwordless sudo (fatal if they can escalate);
//     on failure, captures `sudo -n -iu target -- sudo -n -l` output to
//     help the operator find the offending rule.
//  3. Target user can read AND write the work_dir root (fatal if not),
//     plus a best-effort descendant walk producing warnings for paths
//     the target user cannot access.
func PreflightRunAsUser(ctx context.Context, cfg PreflightConfig) PreflightResult {
	result := PreflightResult{Project: cfg.Project, RunAsUser: cfg.RunAsUser}
	if cfg.RunAsUser == "" {
		result.Fatal = append(result.Fatal, errors.New("PreflightRunAsUser: RunAsUser is empty"))
		return result
	}
	if cfg.Runner == nil {
		cfg.Runner = ExecSudoRunner{}
	}
	if cfg.ScanConfig.MaxReport == 0 {
		cfg.ScanConfig = DefaultDescendantScanConfig
	}

	if _, err := cfg.Runner.Run(ctx, "-n", "-iu", cfg.RunAsUser, "--", "/usr/bin/true"); err != nil {
		result.Fatal = append(result.Fatal, fmt.Errorf(
			"project %q: passwordless sudo to user %q is not configured. Add a sudoers rule such as:\n  %s ALL=(%s) NOPASSWD: ALL\nthen restart cc-connect. Underlying error: %w",
			cfg.Project, cfg.RunAsUser, currentUsernameOr("<supervisor>"), cfg.RunAsUser, err))
		return result // subsequent checks are pointless
	}

	if _, err := cfg.Runner.Run(ctx, "-n", "-iu", cfg.RunAsUser, "--", "sudo", "-n", "/usr/bin/true"); err == nil {
		// Escalation succeeded — collect sudo -l from the target's

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Set a non-empty run_as_user in the project's config.toml and restart.
  2. Bypass preflight for projects that intentionally do not use run_as_user isolation.
  3. Inspect result.Fatal after calling PreflightRunAsUser and abort startup when it is non-empty.

Example fix

// before
result := core.PreflightRunAsUser(ctx, cfg)
return nil
// after
result := core.PreflightRunAsUser(ctx, cfg)
if len(result.Fatal) > 0 {
    return fmt.Errorf("preflight failed: %v", result.Fatal)
}
return nil
Defensive patterns

Strategy: validation

Validate before calling

if cfg.RunAsUser == "" {
    return PreflightResult{Fatal: []error{errors.New("run_as_user not configured")}}
}

Try / catch

result := core.PreflightRunAsUser(ctx, cfg)
for _, f := range result.Fatal {
    slog.Error("preflight fatal", "err", f)
}
if len(result.Fatal) > 0 { os.Exit(1) }

Prevention

When it happens

Trigger: PreflightRunAsUser invoked (by runDoctorOne or tests TestPreflightRunAsUser_*) with PreflightConfig.RunAsUser == "" — the empty check is the first gate at core/runas_check.go:85.

Common situations: Starting cc-connect with a project that lacks run_as_user; empty string left in config after commenting out the setting; test harnesses constructing PreflightConfig without the field.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/7061b5f1dd74b21b. Report an issue: GitHub.