vxcontrol/pentagi · error

failed to update container image in database: %w

Error message

failed to update container image in database: %w

What it means

When pulling the caller-requested image fails, RunContainer falls back to the client's default image: it rewrites config.Image to dc.defImage and persists the change with dc.db.UpdateContainerImage. If that DB update fails, the fallback is aborted and the error "failed to update container image in database: %w" is returned (also marking the container Failed via updateContainerInfo). This only occurs on the fallback path — the original image was already unobtainable AND the image correction could not be recorded.

Source

Thrown at backend/pkg/docker/client.go:279

			LocalID: database.StringToNullString(localID),
			ID:      dbContainer.ID,
		})
		if err != nil {
			logger.WithError(err).Error("failed to update container info in database")
		}
	}

	fallbackDockerImage := func() error {
		logger = logger.WithField("image", dc.defImage)
		logger.Warn("try to use default image")
		config.Image = dc.defImage

		dbContainer, err = dc.db.UpdateContainerImage(ctx, database.UpdateContainerImageParams{
			Image: config.Image,
			ID:    dbContainer.ID,
		})
		if err != nil {
			return fmt.Errorf("failed to update container image in database: %w", err)
		}

		if err := dc.pullImage(ctx, config.Image); err != nil {
			return fmt.Errorf("failed to pull default image '%s': %w", config.Image, err)
		}

		return nil
	}

	if err := dc.pullImage(ctx, config.Image); err != nil {
		logger.WithError(err).Warnf("failed to pull image '%s' and using default image", config.Image)
		if err := fallbackDockerImage(); err != nil {
			defer updateContainerInfo(database.ContainerStatusFailed, "")
			return database.Container{}, err
		}
	}

	logger.Info("creating container")

View on GitHub (pinned to ea665308ba)

Solutions

  1. Check the wrapped cause and Postgres health (pg_isready, docker compose logs db).
  2. Check for concurrent deletion: another agent may have stopped/removed the flow while the pull was timing out; serialize flow lifecycle.
  3. Reduce the pull failure latency (pre-pull images, use a local registry mirror) so the row is still valid at fallback time.
  4. Check DB disk space and connection pool stats; raise max_connections or pool size if exhausted.

Example fix

// before: long pull timeout lets row get cleaned up mid-flight
ctx := context.Background()
// after: bound pull and retry fallback promptly
ctx, cancel := context.WithTimeout(ctx, 2*time.Minute)
defer cancel()
Defensive patterns

Strategy: try-catch

Validate before calling

// Reduce window for DB loss: pre-pull commonly used images at startup so the
// fallback path is rarely taken, and check DB health before long operations:
if err := db.Ping(ctx); err != nil { return err }

Try / catch

if err := dc.pullImage(ctx, config.Image); err != nil {
    if err := fallbackDockerImage(); err != nil {
        if strings.Contains(err.Error(), "failed to update container image in database") {
            // row vanished or DB down: retry DB update with backoff before giving up
            return retryWithBackoff(3, func() error { return updateImageRow() })
        }
        return err
    }
}

Prevention

When it happens

Trigger: Image pull of the requested image failed (bad tag, registry auth, network), triggering fallbackDockerImage(); then dc.db.UpdateContainerImage fails: DB down, container row already deleted, constraint violation, or connection pool exhaustion.

Common situations: Postgres connection dropped between CreateContainer and the fallback update (long pull timeout); a concurrent StopContainer/RemoveContainer deleted the row while a slow pull was failing; DB disk full so the UPDATE errors.

Related errors


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