{"record":{"id":"4bed9c82c921b298","repo":"badges/shields","slug":"recordtype-tolowercase-not-found","errorCode":null,"errorMessage":"${recordType.toLowerCase()} not found","messagePattern":"(.+?) not found","errorType":"exception","errorClass":"NotFound","httpStatus":404,"severity":"error","filePath":"services/azure-devops/azure-devops-build.service.js","lineNumber":173,"sourceCode":"    buildId,\n    stage,\n    job,\n    httpErrors,\n  ) {\n    const url = `https://dev.azure.com/${organization}/${projectId}/_apis/build/builds/${buildId}/timeline`\n    const { records } = await this.fetch({\n      url,\n      options: {},\n      schema: timelineSchema,\n      httpErrors,\n    })\n    const recordType = job ? 'Job' : 'Stage'\n    const recordName = job || stage\n    const record = records.find(\n      r => r.type === recordType && r.name === recordName,\n    )\n    if (!record) {\n      throw new NotFound({\n        prettyMessage: `${recordType.toLowerCase()} not found`,\n      })\n    }\n    return record.result\n  }\n\n  async handle(\n    { organization, projectId, definitionId, branch },\n    { stage, job },\n  ) {\n    const httpErrors = {\n      404: 'build pipeline not found',\n    }\n    // Microsoft documentation: https://docs.microsoft.com/en-us/rest/api/azure/devops/build/builds/list\n    const url = `https://dev.azure.com/${organization}/${projectId}/_apis/build/builds`\n    const options = {\n      searchParams: {\n        definitions: definitionId,","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/badges/shields/blob/766fd8bc89a90b8534dc573ab72dec30215ab1ec/services/azure-devops/azure-devops-build.service.js#L155-L191","documentation":"After fetching a build's timeline, getStageOrJobResult searches the timeline records for a record whose type ('Stage' or 'Job') and name match the requested stage/job. If no matching record exists it throws NotFound with '<stage|job> not found'. The build exists, but the named stage or job does not appear in its timeline.","triggerScenarios":"Requesting an Azure DevOps build badge with a stage or job query parameter whose name does not match any timeline record: records.find(r => r.type === recordType && r.name === recordName) returns undefined, throwing NotFound with 'stage not found' or 'job not found'.","commonSituations":"Renaming a stage/job in azure-pipelines.yml while old badge URLs still reference the old name; typos in the stage/job name (names are case-sensitive here); querying a job that only exists in some branches or conditional compilations; YAML path separators vs. display names.","solutions":["Check the stage/job name in the badge URL against the current azure-pipelines.yml and update it after renames.","Verify the referenced stage/job actually runs in the build for the queried branch.","Match the name exactly as it appears in the timeline (display name vs. YAML identifier can differ)."],"exampleFix":"// before\n.../build/myorg/myproj/42?stage=BuildOld\n// after\n.../build/myorg/myproj/42?stage=Build","handlingStrategy":"validation","validationCode":"const timeline = await fetchBuildTimeline(org, project, buildId)\nconst exists = timeline.records.some(\n  r => r.type === 'Stage' && r.name === stageName\n)\nif (!exists) throw new Error(`Stage '${stageName}' not in build timeline`)","typeGuard":"function findRecord(records, type, name) {\n  return records.find(r => r.type === type && r.name === name) ?? null\n}","tryCatchPattern":"try {\n  return await service.result(params)\n} catch (e) {\n  if (e instanceof NotFound) return renderBadge('unknown stage/job')\n  throw e\n}","preventionTips":["Keep badge URLs in sync with stage/job names in azure-pipelines.yml","Use exact timeline names (display names may differ from YAML ids)","Verify the stage/job runs on the queried branch"],"tags":["azure-devops","ci","not-found","stage","job"],"backgroundTag":"resource-not-found","analyzedSha":"766fd8bc89a90b8534dc573ab72dec30215ab1ec","analyzedAt":"2026-08-30T01:40:27.499Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}