@@ -19,6 +19,15 @@ const bearerPrefix = "Bearer "
1919const responseBodyStr = "response body"
2020const invalidImageReferenceFormat = "invalid image reference: %w"
2121
22+ // ErrImageNotFound is returned when the registry responds with 404 for a manifest request.
23+ type ErrImageNotFound struct {
24+ Image string
25+ }
26+
27+ func (e * ErrImageNotFound ) Error () string {
28+ return fmt .Sprintf ("image not found: %s" , e .Image )
29+ }
30+
2231// ImageReference represents a parsed Docker image reference
2332type ImageReference struct {
2433 Registry string
@@ -228,7 +237,7 @@ func (c *RegistryClient) fetchToken(realm, service, scope string, creds Registry
228237 if resp .StatusCode != http .StatusOK {
229238 body , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
230239 log .WithField ("response_body" , string (body )).WithField ("status_code" , resp .StatusCode ).Debug ("Authentication request failed" )
231- return "" , fmt .Errorf ("authentication failed with status %d" , resp .StatusCode )
240+ return "" , fmt .Errorf ("authentication failed ( status %d): check credentials or verify the image exists " , resp .StatusCode )
232241 }
233242
234243 var tokenResp struct {
@@ -328,7 +337,14 @@ func (c *RegistryClient) GetPlatforms(ref ImageReference) ([]Platform, error) {
328337 }
329338 defer closeWithLog (resp .Body , responseBodyStr )
330339
331- if resp .StatusCode != http .StatusOK {
340+ switch resp .StatusCode {
341+ case http .StatusOK :
342+ // handled below
343+ case http .StatusNotFound :
344+ return nil , & ErrImageNotFound {Image : ref .Repository + ":" + ref .Tag }
345+ case http .StatusUnauthorized , http .StatusForbidden :
346+ return nil , fmt .Errorf ("access denied (status %d): check credentials or verify the image exists" , resp .StatusCode )
347+ default :
332348 body , _ := io .ReadAll (resp .Body )
333349 return nil , fmt .Errorf ("failed to get manifest: %d - %s" , resp .StatusCode , string (body ))
334350 }
@@ -414,7 +430,14 @@ func (c *RegistryClient) getManifest(ref ImageReference, platform Platform) (*Ma
414430 }
415431 defer closeWithLog (resp .Body , responseBodyStr )
416432
417- if resp .StatusCode != http .StatusOK {
433+ switch resp .StatusCode {
434+ case http .StatusOK :
435+ // handled below
436+ case http .StatusNotFound :
437+ return nil , & ErrImageNotFound {Image : ref .Repository + ":" + ref .Tag }
438+ case http .StatusUnauthorized , http .StatusForbidden :
439+ return nil , fmt .Errorf ("access denied (status %d): check credentials or verify the image exists" , resp .StatusCode )
440+ default :
418441 body , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
419442 return nil , fmt .Errorf ("failed to get manifest: %d - %s" , resp .StatusCode , string (body ))
420443 }
0 commit comments