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() {
returnView on GitHub (pinned to ea665308ba)
Solutions
- Check the provider implementation used for this subtask — make it return only providers.PerformResultWaiting/Done/Error.
- If a new PerformResult enum value was added in pkg/providers, extend the switch in subtaskWorker.Run to handle it.
- Rebuild the backend binary so provider package and controller are from the same version (go mod tidy && go build).
- 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
- Only return PerformResult enum constants from provider implementations — never raw ints.
- Rebuild the whole backend binary after upgrading pkg/providers so enum values are consistent.
- Add a unit test asserting every provider returns one of the three known results.
- Handle new PerformResult enum values in subtaskWorker.Run immediately when added upstream.
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
- failed to switch provider: %w
- flow %d is in unknown status: %s
- failed to bulk-update flows provider name: %w
- failed to bulk-update assistants provider name: %w
- failed to update subtask %d status to created: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/319b7f4442a8eb76.
Report an issue: GitHub.