@@ -113,18 +113,26 @@ func (m *manager) CreateImage(ctx context.Context, req CreateImageRequest) (*Ima
113113
114114 // Check if we already have this digest (deduplication)
115115 if meta , err := readMetadata (m .paths , ref .Repository (), ref .DigestHex ()); err == nil {
116- // We have this digest already
117- if meta .Status == StatusReady && ref .Tag () != "" {
118- // Update tag symlink to point to current digest
119- // (handles case where tag moved to new digest)
120- createTagSymlink (m .paths , ref .Repository (), ref .Tag (), ref .DigestHex ())
121- }
122- img := meta .toImage ()
123- // Add queue position if pending
124- if meta .Status == StatusPending {
125- img .QueuePosition = m .queue .GetPosition (meta .Digest )
116+ // Don't cache failed builds - allow retry
117+ if meta .Status == StatusFailed {
118+ // Clean up the failed build directory so we can retry
119+ digestDir := filepath .Join (m .paths .ImagesDir (), ref .Repository (), ref .DigestHex ())
120+ os .RemoveAll (digestDir )
121+ // Fall through to re-queue the build
122+ } else {
123+ // We have this digest already (ready, pending, pulling, or converting)
124+ if meta .Status == StatusReady && ref .Tag () != "" {
125+ // Update tag symlink to point to current digest
126+ // (handles case where tag moved to new digest)
127+ createTagSymlink (m .paths , ref .Repository (), ref .Tag (), ref .DigestHex ())
128+ }
129+ img := meta .toImage ()
130+ // Add queue position if pending
131+ if meta .Status == StatusPending {
132+ img .QueuePosition = m .queue .GetPosition (meta .Digest )
133+ }
134+ return img , nil
126135 }
127- return img , nil
128136 }
129137
130138 // Don't have this digest yet, queue the build
@@ -156,15 +164,22 @@ func (m *manager) ImportLocalImage(ctx context.Context, repo, reference, digest
156164
157165 // Check if we already have this digest (deduplication)
158166 if meta , err := readMetadata (m .paths , ref .Repository (), ref .DigestHex ()); err == nil {
159- // We have this digest already
160- if meta .Status == StatusReady && ref .Tag () != "" {
161- createTagSymlink (m .paths , ref .Repository (), ref .Tag (), ref .DigestHex ())
162- }
163- img := meta .toImage ()
164- if meta .Status == StatusPending {
165- img .QueuePosition = m .queue .GetPosition (meta .Digest )
167+ // Don't cache failed builds - allow retry
168+ if meta .Status == StatusFailed {
169+ digestDir := filepath .Join (m .paths .ImagesDir (), ref .Repository (), ref .DigestHex ())
170+ os .RemoveAll (digestDir )
171+ // Fall through to re-queue the build
172+ } else {
173+ // We have this digest already
174+ if meta .Status == StatusReady && ref .Tag () != "" {
175+ createTagSymlink (m .paths , ref .Repository (), ref .Tag (), ref .DigestHex ())
176+ }
177+ img := meta .toImage ()
178+ if meta .Status == StatusPending {
179+ img .QueuePosition = m .queue .GetPosition (meta .Digest )
180+ }
181+ return img , nil
166182 }
167- return img , nil
168183 }
169184
170185 // Don't have this digest yet, queue the build
0 commit comments