{"record":{"id":"54f80d8d427b8af9","repo":"nektos/act","slug":"expected-format-owner-repo-github-workflows","errorCode":null,"errorMessage":"expected format {owner}/{repo}/.github/workflows/{filename}@{ref}. Actual '%s' Input string was not in a correct format","messagePattern":"expected format (.+?)/(.+?)/\\.github/workflows/(.+?)@(.+?)\\. Actual '(.+?)' Input string was not in a correct format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/runner/reusable_workflow.go","lineNumber":28,"sourceCode":"\t\"path\"\n\t\"regexp\"\n\t\"sync\"\n\n\t\"github.com/nektos/act/pkg/common\"\n\t\"github.com/nektos/act/pkg/common/git\"\n\t\"github.com/nektos/act/pkg/model\"\n)\n\nfunc newLocalReusableWorkflowExecutor(rc *RunContext) common.Executor {\n\treturn newReusableWorkflowExecutor(rc, rc.Config.Workdir, rc.Run.Job().Uses)\n}\n\nfunc newRemoteReusableWorkflowExecutor(rc *RunContext) common.Executor {\n\tuses := rc.Run.Job().Uses\n\n\tremoteReusableWorkflow := newRemoteReusableWorkflow(uses)\n\tif remoteReusableWorkflow == nil {\n\t\treturn common.NewErrorExecutor(fmt.Errorf(\"expected format {owner}/{repo}/.github/workflows/{filename}@{ref}. Actual '%s' Input string was not in a correct format\", uses))\n\t}\n\n\t// uses with safe filename makes the target directory look something like this {owner}-{repo}-.github-workflows-{filename}@{ref}\n\t// instead we will just use {owner}-{repo}@{ref} as our target directory. This should also improve performance when we are using\n\t// multiple reusable workflows from the same repository and ref since for each workflow we won't have to clone it again\n\tfilename := fmt.Sprintf(\"%s/%s@%s\", remoteReusableWorkflow.Org, remoteReusableWorkflow.Repo, remoteReusableWorkflow.Ref)\n\tworkflowDir := fmt.Sprintf(\"%s/%s\", rc.ActionCacheDir(), safeFilename(filename))\n\n\tif rc.Config.ActionCache != nil {\n\t\treturn newActionCacheReusableWorkflowExecutor(rc, filename, remoteReusableWorkflow)\n\t}\n\n\treturn common.NewPipelineExecutor(\n\t\tnewMutexExecutor(cloneIfRequired(rc, *remoteReusableWorkflow, workflowDir)),\n\t\tnewReusableWorkflowExecutor(rc, workflowDir, fmt.Sprintf(\"./.github/workflows/%s\", remoteReusableWorkflow.Filename)),\n\t)\n}\n","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/nektos/act/blob/4f411281417e88660bea1c1a1749aa71ae0bd60f/pkg/runner/reusable_workflow.go#L10-L46","documentation":"For a job-level 'uses: {owner}/{repo}/.github/workflows/{file}@{ref}' (reusable workflow called remotely), newRemoteReusableWorkflow parses the string; if it returns nil the format is wrong and act returns this error listing the expected shape. The parser requires exactly owner/repo(/subpath)/.github/workflows/filename@ref over HTTPS-style GitHub references.","triggerScenarios":"A job with 'uses:' that is not a remote reusable workflow path: missing '@ref', missing '.github/workflows/' segment, a local './' path routed to the remote parser, spaces, or a 'docker://'-style reference.","commonSituations":"Converting a local reusable workflow call ('uses: ./.github/workflows/x.yml') and breaking the path; forgetting the @ref; pointing at a file outside .github/workflows.","solutions":["Rewrite the job 'uses:' as owner/repo/.github/workflows/filename.yml@ref, e.g. uses: org/repo/.github/workflows/build.yml@main.","For same-repo calls use the local form: uses: ./.github/workflows/build.yml.","Ensure the filename includes .yml/.yaml and the ref is a branch, tag, or full sha."],"exampleFix":"# before (workflow)\njobs:\n  deploy:\n    uses: org/repo/workflows/deploy.yml\n\n# after\njobs:\n  deploy:\n    uses: org/repo/.github/workflows/deploy.yml@v2","handlingStrategy":"validation","validationCode":"# regex check for remote reusable workflow uses\npython3 - <<'EOF'\nimport re,glob,yaml\npat=re.compile(r'^[^/]+/[^/]+/.*/\\.github/workflows/[^/]+@(refs/)?\\S+$')\nfor f in glob.glob('.github/workflows/*.y*ml'):\n    for jid,job in (yaml.safe_load(open(f)).get('jobs') or {}).items():\n        uses=job.get('uses')\n        if uses and not uses.startswith('./') and not uses.startswith('docker://'):\n            assert pat.match(uses), f'{f} job {jid}: bad reusable workflow uses: {uses!r}'\nprint('reusable uses ok')\nEOF","typeGuard":"func isRemoteReusableWorkflowRef(uses string) bool {\n    i := strings.Index(uses, \"/.github/workflows/\")\n    at := strings.LastIndex(uses, \"@\")\n    return i > 0 && at > i && at < len(uses)-1\n}","tryCatchPattern":null,"preventionTips":["Memorize the shape: owner/repo/.github/workflows/file.yml@ref.","Use ./.github/workflows/file.yml for same-repo calls.","actionlint validates reusable workflow references."],"tags":["reusable-workflow","uses","workflow","act"],"backgroundTag":null,"analyzedSha":"4f411281417e88660bea1c1a1749aa71ae0bd60f","analyzedAt":"2026-08-15T09:19:46.307Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}