Một bước đã ghi mã bản dựng vào GITHUB_OUTPUT nhưng job kế tiếp vẫn nhận chuỗi rỗng. Thường thiếu một tầng ánh xạ: output của step chưa tự trở thành output công khai của job. Bài này dựng workflow hai job nhỏ để nhìn rõ đường đi của một giá trị và xác định chỗ cần kiểm tra khi dữ liệu bị mất.
Tài liệu được đối chiếu ngày 08/11/2026. YAML được phân tích tại máy; các script Bash được kiểm tra cú pháp và chạy với file output, biến môi trường giả lập. Chưa gửi workflow lên GitHub, chưa chạy hosted runner hoặc thực hiện build, upload hay deploy. Workflow không dùng action bên ngoài.
Ba địa chỉ khác nhau của cùng một giá trị
Trong một job, bước tạo dữ liệu cần có id và ghi một output có tên vào file do GITHUB_OUTPUT trỏ tới. Bước sau trong cùng job đọc bằng steps.<id>.outputs.<name>, theo workflow commands.
Muốn qua job khác, khai báo thêm jobs.<id>.outputs. Job nhận khai báo needs rồi đọc từ needs.<id>.outputs.<name>. Hướng dẫn job outputs mô tả hai mắt xích này. Hãy vẽ đường đi cụ thể thay vì dùng chung từ “biến” cho cả ba vị trí.
Workflow tối thiểu có cả người đọc cùng job và khác job
Lưu thành .github/workflows/output-demo.yml trên repository thử nghiệm nếu bạn muốn chạy trên GitHub:
name: Output demo
"on": workflow_dispatch
permissions: {}
jobs:
describe:
runs-on: ubuntu-latest
outputs:
build_label: ${{ steps.metadata.outputs.label }}
steps:
- name: Create label
id: metadata
shell: bash
run: |
set -euo pipefail
printf 'label=%s\n' 'demo-r8' >> "$GITHUB_OUTPUT"
- name: Read inside the same job
env:
BUILD_LABEL: ${{ steps.metadata.outputs.label }}
shell: bash
run: |
set -euo pipefail
test "$BUILD_LABEL" = 'demo-r8'
printf 'Same job: %s\n' "$BUILD_LABEL"
consume:
runs-on: ubuntu-latest
needs: describe
steps:
- name: Read from the previous job
env:
BUILD_LABEL: ${{ needs.describe.outputs.build_label }}
shell: bash
run: |
set -euo pipefail
test "$BUILD_LABEL" = 'demo-r8'
printf 'Next job: %s\n' "$BUILD_LABEL"
label là tên output của step; build_label là tên output của job. Hai tên có thể khác nhau vì dòng ánh xạ chỉ rõ nguồn và đích. Ví dụ cố tình dùng hai tên để dễ nhận ra lỗi gõ nhầm đường dẫn. Giá trị demo-r8 là dữ liệu cố định cho bài học, không phải version sinh từ Git hoặc một hệ thống phát hành.
Quan sát từng mắt xích khi chạy thật
Trong lần chạy thử trên GitHub, kiểm tra bước Create label thành công, sau đó bước đọc cùng job in Same job: demo-r8. Cuối cùng bước ở job consume cần in Next job: demo-r8. Hai lệnh test sẽ làm bước thất bại nếu chuỗi không khớp, giúp tránh một log xanh nhưng dữ liệu thực tế đang rỗng.
Nếu bước cùng job đã đúng mà job sau sai, bắt đầu ở outputs của describe và needs của consume. Nếu cả hai đều sai, quay về id: metadata, tên label và dòng ghi file. Contexts reference giúp kiểm tra địa chỉ của output trong từng phạm vi.
Ghi file output không giống export một biến shell
Trong kiểm tra local, ghi label=demo-r8 vào một file tạm chỉ tạo ra đúng nội dung file. Máy local không có GitHub runner để biến dòng ấy thành context. Tương tự, export BUILD_LABEL=... trong một shell không tự tạo job output cho một máy chạy job khác.
Vì vậy, kiểm tra local của bài chỉ xác nhận script ghi đúng dòng và script nhận xử lý đúng giá trị giả lập. Nó không chứng minh việc GitHub phân giải expression hoặc truyền output qua job; muốn xác nhận phần ấy, chạy workflow thử nghiệm ở trên và đọc kết quả từng job.
Giữ ví dụ đơn giản trước khi truyền dữ liệu động
Ví dụ chỉ truyền chuỗi ngắn một dòng. Với dữ liệu chứa newline, cần dùng định dạng nhiều dòng được GitHub hướng dẫn và chọn delimiter không xuất hiện trong giá trị. Không nối trực tiếp nội dung không tin cậy thành mã shell. Trong workflow này, expression đi qua env, còn Bash đọc biến trong dấu nháy kép.
Đừng dùng output để thay cho kho bí mật hoặc kênh chuyển file lớn. Trước hết hãy chứng minh đường truyền bằng một giá trị nhỏ, sau đó mới nối kết quả build thực tế. Khi đường dẫn step → job → needs rõ ràng, phần lớn lỗi chuỗi rỗng sẽ có vị trí kiểm tra cụ thể.

