vxcontrol/pentagi · error

unknown perform result: %d

Error message

unknown perform result: %d

What it means

Sentinel-style error returned when Provider.PerformAgentChain yields a performResult value outside the known set (Waiting, Done, Error). It indicates the provider adapter returned an undocumented result code — typically a bug in a new or custom provider implementation rather than a runtime condition.

Source

Thrown at backend/pkg/controller/subtask.go:349

	switch performResult {
	case providers.PerformResultWaiting:
		if err := stw.SetStatus(ctx, database.SubtaskStatusWaiting); err != nil {
			stw.handleInterrupting(err)
			return err
		}
	case providers.PerformResultDone:
		if err := stw.SetStatus(ctx, database.SubtaskStatusFinished); err != nil {
			stw.handleInterrupting(err)
			return fmt.Errorf("failed to set subtask %d status to finished: %w", subtaskID, err)
		}
	case providers.PerformResultError:
		if err := stw.SetStatus(ctx, database.SubtaskStatusFailed); err != nil {
			stw.handleInterrupting(err)
			return fmt.Errorf("failed to set subtask %d status to failed: %w", subtaskID, err)
		}
	default:
		return fmt.Errorf("unknown perform result: %d", performResult)
	}

	return nil
}

// handleInterrupting sets this subtask (and task/flow via SetStatus back-propagation)
// to Waiting when err is context.Canceled or context.DeadlineExceeded. Use after the subtask
// was advanced past Waiting (e.g. Running) but the run aborts before PerformAgentChain's
// normal error handler, or when a late SetStatus fails with a context interruption.
func (stw *subtaskWorker) handleInterrupting(err error) {
	if err == nil {
		return
	}
	if !errors.Is(err, context.Canceled) && !errors.Is(err, context.DeadlineExceeded) {
		return
	}
	if stw.IsCompleted() {
		return

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the provider implementation used for this subtask — make it return only providers.PerformResultWaiting/Done/Error.
  2. If a new PerformResult enum value was added in pkg/providers, extend the switch in subtaskWorker.Run to handle it.
  3. Rebuild the backend binary so provider package and controller are from the same version (go mod tidy && go build).
  4. Log the raw performResult value to identify which provider/constant leaked through.

Example fix

// before: custom provider returns an unhandled value
return 42, nil
// after: return only enum values
return providers.PerformResultDone, nil
Defensive patterns

Strategy: validation

Validate before calling

switch r := performResult; r {
case providers.PerformResultWaiting, providers.PerformResultDone, providers.PerformResultError:
    // ok
default:
    return fmt.Errorf("provider returned invalid perform result %d", r)
}

Type guard

func validPerformResult(r providers.PerformResult) bool {
    switch r {
    case providers.PerformResultWaiting, providers.PerformResultDone, providers.PerformResultError:
        return true
    }
    return false
}

Try / catch

if err := stw.Run(ctx); err != nil {
    if strings.HasPrefix(err.Error(), "unknown perform result") {
        logrus.WithError(err).Error("provider contract violation — check provider version")
        return err // non-retryable
    }
}

Prevention

When it happens

Trigger: subtaskWorker.Run()'s switch on performResult falls through to default because the provider returned a PerformResult constant the controller doesn't recognize — e.g. a newly added enum value in pkg/providers not yet handled here, or a custom provider returning a zero-value/overflowed code.

Common situations: Upgrading PentAGI with a custom provider plugin compiled against a newer providers package; hand-written provider adapters returning an int result not from the PerformResult enum; Go version/package version skew between backend modules.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/319b7f4442a8eb76. Report an issue: GitHub.