{"record":{"id":"d33edf57fe3da225","repo":"vxcontrol/pentagi","slug":"failed-to-update-container-image-in-database-w","errorCode":null,"errorMessage":"failed to update container image in database: %w","messagePattern":"failed to update container image in database: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/docker/client.go","lineNumber":279,"sourceCode":"\t\t\tLocalID: database.StringToNullString(localID),\n\t\t\tID:      dbContainer.ID,\n\t\t})\n\t\tif err != nil {\n\t\t\tlogger.WithError(err).Error(\"failed to update container info in database\")\n\t\t}\n\t}\n\n\tfallbackDockerImage := func() error {\n\t\tlogger = logger.WithField(\"image\", dc.defImage)\n\t\tlogger.Warn(\"try to use default image\")\n\t\tconfig.Image = dc.defImage\n\n\t\tdbContainer, err = dc.db.UpdateContainerImage(ctx, database.UpdateContainerImageParams{\n\t\t\tImage: config.Image,\n\t\t\tID:    dbContainer.ID,\n\t\t})\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to update container image in database: %w\", err)\n\t\t}\n\n\t\tif err := dc.pullImage(ctx, config.Image); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to pull default image '%s': %w\", config.Image, err)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tif err := dc.pullImage(ctx, config.Image); err != nil {\n\t\tlogger.WithError(err).Warnf(\"failed to pull image '%s' and using default image\", config.Image)\n\t\tif err := fallbackDockerImage(); err != nil {\n\t\t\tdefer updateContainerInfo(database.ContainerStatusFailed, \"\")\n\t\t\treturn database.Container{}, err\n\t\t}\n\t}\n\n\tlogger.Info(\"creating container\")","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/docker/client.go#L261-L297","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the wrapped cause and Postgres health (pg_isready, docker compose logs db).","Check for concurrent deletion: another agent may have stopped/removed the flow while the pull was timing out; serialize flow lifecycle.","Reduce the pull failure latency (pre-pull images, use a local registry mirror) so the row is still valid at fallback time.","Check DB disk space and connection pool stats; raise max_connections or pool size if exhausted."],"exampleFix":"// before: long pull timeout lets row get cleaned up mid-flight\nctx := context.Background()\n// after: bound pull and retry fallback promptly\nctx, cancel := context.WithTimeout(ctx, 2*time.Minute)\ndefer cancel()","handlingStrategy":"try-catch","validationCode":"// Reduce window for DB loss: pre-pull commonly used images at startup so the\n// fallback path is rarely taken, and check DB health before long operations:\nif err := db.Ping(ctx); err != nil { return err }","typeGuard":null,"tryCatchPattern":"if err := dc.pullImage(ctx, config.Image); err != nil {\n    if err := fallbackDockerImage(); err != nil {\n        if strings.Contains(err.Error(), \"failed to update container image in database\") {\n            // row vanished or DB down: retry DB update with backoff before giving up\n            return retryWithBackoff(3, func() error { return updateImageRow() })\n        }\n        return err\n    }\n}","preventionTips":["Pre-pull the requested and default images on deployment so fallbacks are rare.","Avoid concurrent stop/remove of containers while pulls are in flight.","Keep DB sessions alive over long pulls (pool health checks, reasonable timeouts).","Alert on DB disk/connection issues promptly."],"tags":["database","fallback","image-pull"],"backgroundTag":"database-update-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}