{"record":{"id":"847705ba519773d9","repo":"GoogleContainerTools/skaffold","slug":"s-s-847705","errorCode":null,"errorMessage":"%s. %s","messagePattern":"%s\\. %s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"pkg/skaffold/errors/problem.go","lineNumber":70,"sourceCode":"\t\tErr:         err,\n\t}\n}\n\nfunc (p Problem) Error() string {\n\tdescription := fmt.Sprintf(\"%s.\", p.Err)\n\tif p.Description != nil {\n\t\tdescription = p.Description(p.Err)\n\t}\n\treturn description\n}\n\nfunc (p Problem) AIError(i interface{}, err error) error {\n\tp.Err = err\n\tif p.Suggestion == nil {\n\t\treturn p\n\t}\n\tif suggestions := p.Suggestion(i); len(suggestions) > 0 {\n\t\treturn fmt.Errorf(\"%s. %s\", strings.Trim(p.Error(), \".\"), concatSuggestions(suggestions))\n\t}\n\treturn p\n}\n\nfunc isProblem(err error) (Problem, bool) {\n\tif p, ok := err.(Problem); ok {\n\t\treturn p, true\n\t}\n\treturn Problem{}, false\n}\n\nfunc AddPhaseProblems(phase constants.Phase, problems []Problem) {\n\taddPhaseProblemLock.Lock()\n\tif problemCatalog.allErrors == nil {\n\t\tproblemCatalog = NewProblemCatalog()\n\t}\n\tproblemCatalog.AddPhaseProblems(phase, problems)\n\taddPhaseProblemLock.Unlock()","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/GoogleContainerTools/skaffold/blob/a1189de023efc32d4b8e11f395acc678aa555011/pkg/skaffold/errors/problem.go#L52-L88","documentation":"Problem.AIError wraps a skaffold Problem (an error type carrying cause and description) and, if a Suggestion function is defined and returns entries, re-formats the error as '<problem text>. <suggestions>' using fmt.Errorf. It is not a failure of its own but the rendering step for actionable skaffold errors, invoked e.g. from isOldImageManifestProblem.","triggerScenarios":"Any code path that converts a Problem into a user-facing error while the problem defines a Suggestion callback that returns at least one suggestion string; the returned error's message becomes '%s. %s' (problem error text trimmed of trailing dots, plus concatenated suggestions).","commonSituations":"Developers matching on the error string find the message now includes appended suggestions, breaking exact string comparison; older skaffold versions returned the plain Problem, so downstream string expectations changed between versions.","solutions":["If matching the error in tests or scripts, compare using errors.As against the skaffold Problem type instead of exact string equality","Treat the suggestion suffix as advisory text, not part of the error identity","Update golden-file test expectations to include the appended suggestion text"],"exampleFix":"// before\nif err.Error() == \"some known problem\" { ... }\n// after\nvar p sErrors.Problem\nif errors.As(err, &p) && strings.Contains(p.Error(), \"some known problem\") { ... }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func asProblem(err error) (sErrors.Problem, bool) {\n    var p sErrors.Problem\n    if errors.As(err, &p) {\n        return p, true\n    }\n    return p, false\n}","tryCatchPattern":"if err := run(); err != nil {\n    var p sErrors.Problem\n    if errors.As(err, &p) {\n        log.Errorf(\"%s\", p.Error()) // base problem text, suggestions stripped\n    } else {\n        return err\n    }\n}","preventionTips":["Never rely on exact err.Error() string equality for skaffold errors","Use errors.As/errors.Is against skaffold error types","Regenerate golden test strings when upgrading skaffold versions","Strip suggestion text if comparing messages"],"tags":["error-handling","suggestions","formatting"],"backgroundTag":"actionable-error-wrapping","analyzedSha":"a1189de023efc32d4b8e11f395acc678aa555011","analyzedAt":"2026-09-05T12:09:27.064Z","contentChangedAt":"2026-09-05T12:09:27.064Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}